Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
17.61% covered (danger)
17.61%
1640 / 9311
3.16% covered (danger)
3.16%
3 / 95
CRAP
0.00% covered (danger)
0.00%
0 / 1
WaitingController
17.55% covered (danger)
17.55%
1633 / 9304
3.16% covered (danger)
3.16%
3 / 95
4306252.05
0.00% covered (danger)
0.00%
0 / 1
 beforeFilter
100.00% covered (success)
100.00%
48 / 48
100.00% covered (success)
100.00%
1 / 1
1
 checkHash
0.00% covered (danger)
0.00%
0 / 92
0.00% covered (danger)
0.00%
0 / 1
6
 index
65.54% covered (success)
65.54%
194 / 296
0.00% covered (danger)
0.00%
0 / 1
244.24
 checkProperProfile
40.00% covered (warning)
40.00%
2 / 5
0.00% covered (danger)
0.00%
0 / 1
4.94
 detail
69.63% covered (success)
69.63%
658 / 945
0.00% covered (danger)
0.00%
0 / 1
2344.47
 getStrengthRating
95.00% covered (success)
95.00%
19 / 20
0.00% covered (danger)
0.00%
0 / 1
6
 getLessonHistory
90.32% covered (success)
90.32%
56 / 62
0.00% covered (danger)
0.00%
0 / 1
23.48
 getPrimaryDetails
96.30% covered (success)
96.30%
26 / 27
0.00% covered (danger)
0.00%
0 / 1
6
 getFavCount
95.45% covered (success)
95.45%
21 / 22
0.00% covered (danger)
0.00%
0 / 1
5
 getAlbum
97.83% covered (success)
97.83%
45 / 46
0.00% covered (danger)
0.00%
0 / 1
5
 arrangeTeacherRecommendList
0.00% covered (danger)
0.00%
0 / 71
0.00% covered (danger)
0.00%
0 / 1
812
 checkReservation
88.46% covered (success)
88.46%
23 / 26
0.00% covered (danger)
0.00%
0 / 1
10.15
 start
76.92% covered (success)
76.92%
20 / 26
0.00% covered (danger)
0.00%
0 / 1
12.49
 teacherReserveList
89.21% covered (success)
89.21%
339 / 380
0.00% covered (danger)
0.00%
0 / 1
127.76
 updateChapterOptions
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
3
 result
97.64% covered (success)
97.64%
124 / 127
0.00% covered (danger)
0.00%
0 / 1
7
 loadMoreComments
0.00% covered (danger)
0.00%
0 / 89
0.00% covered (danger)
0.00%
0 / 1
650
 output
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
 isCanCancel
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
30
 convertString
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 getTextbookOption
0.00% covered (danger)
0.00%
0 / 87
0.00% covered (danger)
0.00%
0 / 1
182
 getAllTextbookOption
0.00% covered (danger)
0.00%
0 / 330
0.00% covered (danger)
0.00%
0 / 1
13110
 saveTextbookPreset
0.00% covered (danger)
0.00%
0 / 40
0.00% covered (danger)
0.00%
0 / 1
272
 callLessonAlertandStartButton
0.00% covered (danger)
0.00%
0 / 576
0.00% covered (danger)
0.00%
0 / 1
89102
 loadMoreSelfReviews
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
30
 getUserReviews
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
2
 getReserveAndCancelled
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
1 / 1
3
 triggerOrangeButton
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
30
 deleteLessonOnair
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 1
110
 getTeacherOnlineList
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
12
 getSearchCondition
0.00% covered (danger)
0.00%
0 / 34
0.00% covered (danger)
0.00%
0 / 1
6
 getApologyList
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
2
 limitwarning
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
30
 updatedScheduleColor
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
20
 getAvatarDisabledDates
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
20
 sp_counselor
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 counselor
0.00% covered (danger)
0.00%
0 / 178
0.00% covered (danger)
0.00%
0 / 1
1260
 customersupport
0.00% covered (danger)
0.00%
0 / 152
0.00% covered (danger)
0.00%
0 / 1
756
 counselingGetDisabledDates
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
6
 counselorSlots
0.00% covered (danger)
0.00%
0 / 130
0.00% covered (danger)
0.00%
0 / 1
2070
 avatarSlots
0.00% covered (danger)
0.00%
0 / 219
0.00% covered (danger)
0.00%
0 / 1
4290
 counselingLimit
0.00% covered (danger)
0.00%
0 / 89
0.00% covered (danger)
0.00%
0 / 1
506
 avatarLimit
0.00% covered (danger)
0.00%
0 / 73
0.00% covered (danger)
0.00%
0 / 1
380
 checkCounselingReservationNow
0.00% covered (danger)
0.00%
0 / 58
0.00% covered (danger)
0.00%
0 / 1
110
 spDetail
0.00% covered (danger)
0.00%
0 / 262
0.00% covered (danger)
0.00%
0 / 1
1892
 spAvatarDetail
0.00% covered (danger)
0.00%
0 / 157
0.00% covered (danger)
0.00%
0 / 1
702
 avatar_detail
0.00% covered (danger)
0.00%
0 / 629
0.00% covered (danger)
0.00%
0 / 1
21170
 getTeacherReviews
0.00% covered (danger)
0.00%
0 / 79
0.00% covered (danger)
0.00%
0 / 1
870
 favoriteTextbookCategoryForReview
0.00% covered (danger)
0.00%
0 / 40
0.00% covered (danger)
0.00%
0 / 1
210
 teacherAvatarStatus
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
30
 checkMaintenanceForAlert
0.00% covered (danger)
0.00%
0 / 32
0.00% covered (danger)
0.00%
0 / 1
20
 isAvatar
65.22% covered (success)
65.22%
15 / 23
0.00% covered (danger)
0.00%
0 / 1
24.47
 counselorLatestLessonHistory
0.00% covered (danger)
0.00%
0 / 139
0.00% covered (danger)
0.00%
0 / 1
20
 avatarLatestLessonHistory
0.00% covered (danger)
0.00%
0 / 133
0.00% covered (danger)
0.00%
0 / 1
42
 userAvailPopularTeacher
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
30
 userValidForSSBEDT
80.00% covered (success)
80.00%
4 / 5
0.00% covered (danger)
0.00%
0 / 1
5.20
 loadLiveLessonTeacher
0.00% covered (danger)
0.00%
0 / 60
0.00% covered (danger)
0.00%
0 / 1
756
 sms_questionnaire
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
 avatar_sms_questionnaire
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
 checkCounselorTeacherButtonStatus
0.00% covered (danger)
0.00%
0 / 40
0.00% covered (danger)
0.00%
0 / 1
210
 emergencyLesson
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
56
 teacherBadgeList
0.00% covered (danger)
0.00%
0 / 83
0.00% covered (danger)
0.00%
0 / 1
272
 avatarBadgeList
0.00% covered (danger)
0.00%
0 / 79
0.00% covered (danger)
0.00%
0 / 1
272
 teacherOccupation
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
20
 teacherFeatures
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
30
 getSelfReviews
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
20
 getGenerationRating
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
56
 getGenerationRatingAPI
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
56
 getUserMemo
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 1
30
 getReservationCancellationBreakdown
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
20
 getActiveCampaign
0.00% covered (danger)
0.00%
0 / 535
0.00% covered (danger)
0.00%
0 / 1
21756
 getActiveCampaignStampData
0.00% covered (danger)
0.00%
0 / 177
0.00% covered (danger)
0.00%
0 / 1
272
 showCampaignModal
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
30
 generateTextbookTeacherRecommendAjax
0.00% covered (danger)
0.00%
0 / 67
0.00% covered (danger)
0.00%
0 / 1
342
 setUpAppreciationSelectionModalElementAjax
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
42
 sendTeacherAppreciationAjax
0.00% covered (danger)
0.00%
0 / 69
0.00% covered (danger)
0.00%
0 / 1
420
 ajaxUpdateSystemTrouble
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
90
 reportProblem
0.00% covered (danger)
0.00%
0 / 65
0.00% covered (danger)
0.00%
0 / 1
156
 getApppreciationModal
0.00% covered (danger)
0.00%
0 / 42
0.00% covered (danger)
0.00%
0 / 1
72
 getAppreciationStatus
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
42
 getEvaluationDetail
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
42
 resetLessonReviewModal
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
12
 finishOnlineLesson
0.00% covered (danger)
0.00%
0 / 272
0.00% covered (danger)
0.00%
0 / 1
7310
 getCounselorLessonHistory
0.00% covered (danger)
0.00%
0 / 56
0.00% covered (danger)
0.00%
0 / 1
342
 speakingTestAttendance
0.00% covered (danger)
0.00%
0 / 38
0.00% covered (danger)
0.00%
0 / 1
42
 getRegion
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
56
 getResidenceData
29.17% covered (danger)
29.17%
7 / 24
0.00% covered (danger)
0.00%
0 / 1
45.54
 countTeacherReservedLessons
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
 getLiveCouponResult
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
2
 checkLessonStartButtonNormal
0.00% covered (danger)
0.00%
0 / 671
0.00% covered (danger)
0.00%
0 / 1
112560
 checkLessonStartButtonAvatar
0.00% covered (danger)
0.00%
0 / 653
0.00% covered (danger)
0.00%
0 / 1
94556
 checkLessonStartButtonCounselor
0.00% covered (danger)
0.00%
0 / 30
0.00% covered (danger)
0.00%
0 / 1
30
 checkLessonStartButtonCS
0.00% covered (danger)
0.00%
0 / 43
0.00% covered (danger)
0.00%
0 / 1
72
 updateLessonSystemTrouble
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
20
 setAppreciationModalFinish
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2
3App::uses('AppController', 'Controller');
4App::uses('MyPageController', 'Controller');
5App::uses('SpTeacherController', 'Controller');
6App::uses('myArray', 'Lib');
7App::import('Controller', 'Textbook');
8App::uses('AwsFileServer', 'Lib');
9App::uses('Sanitize', 'Utility');
10
11class WaitingController extends AppController{
12    public $uses = array(
13        'Teacher',
14        'LessonOnair',
15        'LessonSchedule',
16        'LessonScheduleCancel',
17        'LessonLog',
18        'User',
19        'UsersDetail',
20        'UsersCourses',
21        'UsersTicket',
22        'UsersPoint',
23        'ShiftWorkOff',
24        'ShiftWorkOn',
25        'UsersClassEvaluation',
26        'UsersLessonsCountMinus',
27        'DefineMaster',
28        'UsersFavorite',
29        'UserTable',
30        'TeacherFeature',
31        'UsersLastViewedTextbook',
32        'TeacherImage',
33        'TeacherStatus',
34        'TextbookCategory',
35        'Payment',
36        'TextbookCourseConnect',
37        'CountryCode',
38        'PhoneVerifyCheckLog',
39        'CommonTeacherStatus',
40        'LessonOnairsLog',
41        'Textbook',
42        'TeacherBadge',
43        'TeacherCourseBadge',
44        'ShiftWorkHideDate',
45        'UsersFavorite',
46        'CounselingTable',
47        'Counseling',
48        'TeacherDetail',
49        'Timezone',
50        'TeacherWeeklyRating',
51        'PopularTeacherCampaignPeriod',
52        'BlockList',
53        'Avatar',
54        'HomeBasedRankBasicAmountLog',
55        'HomeBasedRankBasicAmount',
56        'UsersMemo',
57        'GlobalTextbookCategory',
58        'TeacherRankCoin',
59        'UserTextbookFavorite',
60        'UserSearchCondition',
61        'UsersTextbookInfo',
62        'Corporate',
63        'TeacherStudentConnection',
64        'TextbookConnect',
65        'TeacherStudentConnection',
66        'TeacherFeatureRating',
67        'ChatHistory',
68        'TeacherTextbookStat',
69        'LessonOnairsViewer',
70        'FeatureRatingItem',
71        'UsersFavoriteCategoriesTeacher',
72        'LessonOnairsLogTimeExtension',
73        'LessonOnairsViewersLog',
74        'UsersTextbookInfo',
75        'UsersFavoriteCategories',
76        'UserFeatureRatingLastVoted',
77        'TeacherDetails',
78        'UserFirstLesson',
79        'AppreciationMessage',
80        'UsersClassEvaluationFeatureRating',
81        'ViewersClassEvaluation',
82        'TeacherCoinBox',
83        'LessonOnairsLogTable',
84        'LessonBookmark',
85        'CampaignPcBanner',
86        'ReservationCoin',
87        'CountryRegion',
88        'CampaignInstructor',
89        'CampaignTagControl',
90        'ProhibitedWord',
91        'TitleThresholdTeacher',
92        'ViewerFeatureRatingLastVoted',
93        'PlanTeacherCategoryBlock'
94    );
95
96    public $helpers = array('Html', 'Form');
97    public $selfReviewLimit = 10;
98    public $components = array('Cookie'); //NC-3096 add cookie
99    public $defaultMemoryLimit = null;
100    public $blockMemberSettings = [];
101    public function beforeFilter() {
102        parent::beforeFilter();
103        //NC-3096 cookies
104        $this->Cookie->name = 'searchTeacherForm';
105        $this->Cookie->time = 86400 ;  // 1 day
106        $this->Cookie->domain = $_SERVER['SERVER_NAME'];
107
108        $allowActionArr = array(
109            'index',
110            'detail',
111            'avatar_detail',
112            'avatarSlots',
113            'teacherReserveList',
114            'loadMoreComments',
115            'isShiftWorkCancelled',
116            'callLessonAlertandStartButton',
117            'counselor',
118            'sp_counselor',
119            'counselorSlots',
120            'checkCounselingReservationNow',
121            'teacherAvatarStatus',
122            'getTeacherReviews',
123            'loadLiveLessonTeacher',
124            'limitwarning',
125            'isCanCancel',
126            'teacherBadgeList',
127            'teacherOccupation',
128            'teacherFeatures',
129            'getSelfReviews',
130            'getGenerationRating',
131            'getReservationCancellationBreakdown',
132            'getAlbum',
133            'getFavCount',
134            'getLessonHistory',
135            'getStrengthRating',
136            'getGenerationRatingAPI',
137            'avatarBadgeList',
138            'getPrimaryDetails',
139            'finishOnlineLesson',
140            'speakingTestAttendance',
141            'getRegion',
142            'countTeacherReservedLessons',
143            'checkLessonStartButtonNormal',
144            'checkLessonStartButtonAvatar'
145        );
146
147        $phoneNumbers = $this->CountryCode->getCountryCodesWithSmsAuth();
148        $this->set('phoneNumbers', $phoneNumbers);
149
150        $this->Auth->allow($allowActionArr);
151        //Timezone timedifference
152        $this->set('timeDiffSecond', $this->timeDiffSecond);
153        $this->defaultMemoryLimit = ini_get("memory_limit");
154        $this->blockMemberSettings = $this->PlanTeacherCategoryBlock->getPlanTeacherCategoryBlock($this->sharedUserData['User']);
155    }
156
157    private function checkHash($table , $chatHash) { //returns data if chat_hash exist
158        $fields = array(
159            $table.'.id',
160            $table.'.teacher_id',
161            $table.'.user_id',
162            $table.'.start_time',
163            $table.'.end_time',
164            $table.'.lesson_type', // NC-3824
165            $table.'.lesson_finish', // NC-3824,
166            $table.'.created', // NC-3824
167            $table.'.user_agent',
168            $table.'.lesson_system_trouble',
169            $table.'.connect_id', // NC-5884
170            $table.'.live_lesson_flg',
171            $table.'.connect_id',
172            $table.'.lesson_schedule_id',
173            $table.'.counselor_flag',
174            $table.'.textbook_category_id',
175            'teacher.id',
176            'teacher.name',
177            'teacher.jp_name',
178            'teacher.image_url',
179            'teacher.home_flg', // NC-3824
180            'teacher.rank_coin_id', // NC-3824
181            'teacher.first_lesson_date', // NC-3824
182            'teacher.promote_date', // NC-3824
183            'TeacherDetail.referrer_id', // NC-3824
184            'teacher.counseling_flg', //NC-4589
185            'teacher.avatar_id',
186            'teacher.avatar_flg',
187            'teacher.avatar_parent_flg',
188            'User.nickname',
189            'User.created',
190            'User.fail_flg',
191            'User.charge_flg',
192            'User.birthday',
193            'User.birthday_show_flg',
194            'Connect.id',
195            'Connect.category_id',
196            'Connect.textbook_id',
197            'User.network_review_flg',
198            'User.textbook_review_flg',
199            'User.teacher_review_flg',
200            'User.next_textbook_flg',
201            'User.lesson_review_flg'
202        );
203
204        if ($table == 'LessonOnairsLog') {
205            array_push($fields, 'LessonOnairsLog.onair_id');
206        }
207
208        $data = array(  
209        'conditions' => 
210              array(
211                $table.'.chat_hash' => $chatHash
212               ),  
213        'joins' =>
214                  array(
215                    array(
216                        'table' => 'teachers',
217                        'alias' => 'teacher',
218                        'type' => 'left',
219                        'foreignKey' => false,
220                        'conditions' => array(
221                            'teacher.id ='.$table.'.teacher_id'
222                        )
223                    ),        
224                    array(
225                        'table' => 'users',
226                        'alias' => 'User',
227                        'type' => 'left',
228                        'conditions' => array(
229                            'User.id = '.$table.'.user_id'
230                        )
231                    ),
232                    array(
233                        'table' => 'textbook_connects',
234                        'alias' => 'Connect',
235                        'type' => 'left',
236                        'conditions' => array(
237                            'Connect.id = '.$table.'.connect_id'
238                        )
239                    ),
240                    array( // NC-3824
241                        'table' => 'teacher_details',
242                        'alias' => 'TeacherDetail',
243                        'type' => 'left',
244                        'conditions' => array(
245                            'TeacherDetail.teacher_id = '.$table.'.teacher_id'
246                        )
247                    )
248                ),
249
250        'fields' => $fields,                
251        'order' => array($table.'.id' => 'DESC')            
252        );
253
254        return $data;
255    }
256
257    /**
258 * @api {get} /user/:language/waiting index()
259 * @apiName index
260 * @apiGroup Waiting
261 * @apiDescription Retrieves the index page for the waiting area in Native Camp. It returns various information about the user, teachers, and campaigns.
262 *
263 * @apiParam {String} language The language code for the page.
264 * 
265 * @apiSuccess {Object[]} allBanners The list of campaign banners.
266 * @apiSuccess {String} allBanners.id The ID of the banner.
267 * @apiSuccess {String} allBanners.campaign_url The URL of the campaign.
268 * @apiSuccess {String} allBanners.start The start date of the campaign.
269 * @apiSuccess {String} allBanners.end The end date of the campaign.
270 * @apiSuccess {String} allBanners.image_url The image URL of the campaign.
271 * @apiSuccess {String} allBanners.event_tracking_tag The event tracking tag of the campaign.
272 * @apiSuccess {String} allBanners.display_position The display position of the campaign.
273 * @apiSuccess {Object} searchCount The count of saved search conditions.
274 * @apiSuccess {Object} userpoint The user points.
275 * @apiSuccess {String} localizeDir The localization directory.
276 * @apiSuccess {Object} selectOptions The select options for the teacher search.
277 * @apiSuccess {Object} selectOptions.availability The availability options.
278 * @apiSuccess {Object} selectOptions.classification The classification options.
279 * @apiSuccess {String} headtext The head text for the page.
280 * @apiSuccess {Object[]} badges The list of badges.
281 * @apiSuccess {Boolean} isLoggedIn Indicates if the user is logged in.
282 * @apiSuccess {Object} userData The user data.
283 * @apiSuccess {Object} userData.User The user object.
284 * @apiSuccess {String} userData.User.id The ID of the user.
285 * @apiSuccess {String} userData.User.currency_code The currency code of the user.
286 * @apiSuccess {String} userData.User.card_company The card company of the user.
287 * @apiSuccess {Object} userDataObj The user data object.
288 * @apiSuccess {Number} paymentPlanId The payment plan ID of the user.
289 * @apiSuccess {Number} userLang The language ID of the user.
290 * @apiSuccess {Object[]} seriesSpecialArr The list of special series.
291 * @apiSuccess {Object} seriesSelected The selected series.
292 * @apiSuccess {Object} counselor The counselor object.
293 * @apiSuccess {String} counselor.name The name of the counselor.
294 * @apiSuccess {String} counselor.jp_name The Japanese name of the counselor.
295 * @apiSuccess {String} counselor.image_url The image URL of the counselor.
296 * @apiSuccess {String} counselor.country_name The country name of the counselor.
297 * @apiSuccess {Boolean} isHide Indicates if the counselor is hidden.
298 * @apiSuccess {Object[]} favId The list of favorite teacher IDs.
299 * @apiSuccess {Object[]} teacherFavs The list of favorite teachers with colors.
300 * @apiSuccess {Object[]} teacherFavsColors The list of favorite teacher colors.
301 * @apiSuccess {Object[]} avatarActiveId The list of active avatar IDs.
302 * @apiSuccess {Boolean} teddyFav Indicates if the teddy avatar is favorited.
303 * @apiSuccess {Object[]} occupationData The list of teacher occupations.
304 * @apiSuccess {Object} counselorLampStatus The counselor lamp status.
305 * @apiSuccess {Boolean} hideCouselorFromMember Indicates if the counselor information should be hidden from the member.
306 * @apiSuccess {Boolean} is_lite_plan_user Indicates if the user is on a lite plan.
307 * @apiSuccess {Object[]} teacherList The list of teachers.
308 * @apiSuccess {Object[]} regions The list of regions.
309 * @apiSuccess {Object[]} coinData The list of coin data.
310 * @apiSuccess {Object} searchData The search data.
311 * @apiSuccess {Boolean} isLogin Indicates if the user is logged in.
312 * @apiSuccess {Number} savedConditionsCount The count of saved search conditions.
313 * @apiSuccess {Object} preset The preset textbook information.
314 * @apiSuccess {Object} searchCondition The search condition.
315 * @apiSuccess {Object[]} featureFilter The list of feature filters.
316 * @apiSuccess {Object} user The user object.
317 * @apiSuccess {String} user.id The ID of the user.
318 * @apiSuccess {String} user.name The name of the user.
319 * @apiSuccess {String} disconnectionChatHash The disconnection chat hash.
320 * @apiSuccess {Object[]} coins The list of coins.
321 * @apiSuccess {Object} campaignTagSearch The campaign tag search status.
322 *
323 * @apiSuccessExample {json} Success-Response:
324 *     {
325 *         "allBanners": [
326 *             {
327 *                 "id": "1",
328 *                 "campaign_url": "http://example.com/campaign",
329 *                 "start": "2023-12-01",
330 *                 "end": "2023-12-31",
331 *                 "image_url": "http://example.com/image.jpg",
332 *                 "event_tracking_tag": "tag1",
333 *                 "display_position": "top"
334 *             }
335 *         ],
336 *         "searchCount": 5,
337 *         "userpoint": 100,
338 *         "localizeDir": "en",
339 *         "selectOptions": {
340 *             "availability": {...},
341 *             "classification": {...}
342 *         },
343 *         "headtext": "Welcome to the waiting area",
344 *         "badges": [...],
345 *         "isLoggedIn": true,
346 *         "userData": {
347 *             "User": {
348 *                 "id": "123",
349 *                 "currency_code": "USD",
350 *                 "card_company": "Visa"
351 *             }
352 *         },
353 *         "userDataObj": {...},
354 *         "paymentPlanId": 1,
355 *         "userLang": 1,
356 *         "seriesSpecialArr": [...],
357 *         "seriesSelected": {...},
358 *         "counselor": {
359 *             "name": "John Doe",
360 *             "jp_name": "ジョン・ドウ",
361 *             "image_url": "http://example.com/image.jpg",
362 *             "country_name": "Japan"
363 *         },
364 *         "isHide": false,
365 *         "favId": [...],
366 *         "teacherFavs": [...],
367 *         "teacherFavsColors": [...],
368 *         "avatarActiveId": [...],
369 *         "teddyFav": true,
370 *         "occupationData": [...],
371 *         "counselorLampStatus": {...},
372 *         "hideCouselorFromMember": false,
373 *         "is_lite_plan_user": true,
374 *         "teacherList": [...],
375 *         "regions": [...],
376 *         "coinData": [...],
377 *         "searchData": {...},
378 *         "isLogin": true,
379 *         "savedConditionsCount": 5,
380 *         "preset": {...},
381 *         "searchCondition": {...},
382 *         "featureFilter": [...],
383 *         "user": {
384 *             "id": "123",
385 *             "name": "John Doe"
386 *         },
387 *         "disconnectionChatHash": "abc123",
388 *         "coins": [...],
389 *         "campaignTagSearch": {...}
390 *     }
391 *
392 * @apiError {String} status The status of the request (NG).
393 * @apiError {String} message The error message.
394 *
395 * @apiErrorExample {json} Error-Response:
396 *     {
397 *         "status": "NG",
398 *         "message": "Invalid request."
399 *     }
400 * 
401 * @apiSampleRequest off
402 */
403    public function index() {
404        // NJ-37582 redirect to appointment
405        $this->redirect('/appointment');
406        
407        $this->Teacher->hasAfterFind = true;
408        //mobile view only
409        
410        if ($this->RequestHandler->isMobile()) {
411            $this->layout = 'mobile';
412            $userpoints = $this->UsersPoint->getCurrentUserPoint($this->Auth->user('id'));
413
414            myTools::initializeApiTunnel(['SearchConditionsController']);
415
416            $displayRestrictionParams = array(
417                'lang' => $this->localizeDir
418            );
419
420            $searchConditions = new SearchConditionsController();
421            $params= array(
422                "users_api_token" => $this->Auth->user('api_token'),
423                "nc_terminal_type" => Configure::read('nc_terminal_type.pc'),
424                "displayRestrictionParams" => $displayRestrictionParams
425            );
426            $searchConditions->params = $params;
427
428            $search = json_decode($searchConditions->index(), true);
429            $savedSearchCount = count($search['conditions'] ?? []);
430
431            $this->set('searchCount', $savedSearchCount);
432            $this->set('userpoint', $userpoints);
433            $this->set('localizeDir',  $this->localizeDir);
434            return $this->render('/Mobile/Teacher/index');
435        }
436
437        $params = $this->params->query;
438        if (isset($params['stealth'])) {
439            TeacherTable::setStealthSettings($this->Cookie, $params['stealth']);
440        }
441        $selectOptions = array(
442            'availability' => TeacherTable::teacherAvailSelect2(),
443            //'nationality' => TeacherTable::teacherLocationSelect()
444            'classification' => TeacherTable::teacherClassificationSelect()
445        );
446        $this->set('selectOptions', $selectOptions);
447        $this->set('headtext', Configure::read('my.meta.waiting-index.headtext'));
448        $this->set('badges', TeacherBadgeTable::displayBadges());
449        $this->set('isLoggedIn', $this->Auth->loggedIn());
450        
451        $userData = $this->sharedUserData;//use shared user data 
452        // NJ-46: mypage banners
453        $userDataObj = new UserTable($userData['User']);
454        $paymentPlanId = $userDataObj->getMembershipTypeIndex();
455        $userLang = $this->CountryCode->getUserLanguageId($this->localizeDir);
456
457        // - conditions
458        $conditions = array(
459            'CampaignPcBanner.status' => 1,
460            'CampaignPcBannerCurrency.currency_code' => $userData['User']['currency_code'],
461            'CampaignPcBannerLanguage.language_id' => $userLang,
462        );
463
464        if ($userData['User']['card_company']) {
465            $conditions['CampaignPcBanner.payment_company LIKE'] = '%' . $userData['User']['card_company'] . '%';
466        }
467
468        if ($paymentPlanId) {
469            $conditions['FIND_IN_SET(?, CampaignPcBanner.user_status)'] = $paymentPlanId;
470        }
471        $this->log("[CampaignSettingsModal] conditions -> " .  json_encode($conditions), "debug");
472
473        $this->CampaignPcBanner->openDBReplica();
474        $allBanners = $this->CampaignPcBanner->find('all', array(
475            'fields' => array(
476                'CampaignPcBanner.id',
477                'CampaignPcBanner.campaign_url',
478                'CampaignPcBanner.start',
479                'CampaignPcBanner.end',
480                'CampaignPcBanner.image_url',
481                'CampaignPcBanner.event_tracking_tag',
482                'CampaignPcBanner.display_position'
483            ),
484            'conditions' => $conditions,
485            'joins' => array(
486                array(
487                    'table' => 'campaign_pc_banner_currencies',
488                    'alias' => 'CampaignPcBannerCurrency',
489                    'type' => 'LEFT',
490                    'conditions' => array('CampaignPcBannerCurrency.campaign_pc_banner_id = CampaignPcBanner.id')
491                ),
492                array(
493                    'table' => 'campaign_pc_banner_languages',
494                    'alias' => 'CampaignPcBannerLanguage',
495                    'type' => 'LEFT',
496                    'conditions' => array('CampaignPcBannerLanguage.campaign_pc_banner_id = CampaignPcBanner.id')
497                )
498            ),
499            'order' => 'CampaignPcBanner.priority_number ASC',
500            'recursive' => -1,
501        ));
502        $this->CampaignPcBanner->closeDBReplica();
503        $this->set('allBanners', $allBanners);
504
505        //instantiate view
506        $view = new View($this, false);
507        $view->layout = false;
508        //fetch data
509        $this->Teacher->hasAfterFind = true;
510        //NC-4548 from kids text description course
511        if (isset($_COOKIE['fromKidsDescription']) && $_COOKIE['fromKidsDescription'] !== 'null') {
512            $kidsCourseTeacher = array(
513                'sortRadio' => 'status',
514                'statusRadio' => 'all',
515                'teacherFeature' => array(0 => 'kids'),
516                'textbookRadioVal' => '2',
517                'courseOptionSearchCourseId' => '2',
518                'courseOptionChapterId' => '1',
519                'courseOptionLessonTextId' => '209',
520                'courseOptionConnectId' => '1',
521                'seriesOptionSearchTextBookCategoryId' => '11',
522                'badgeIds' => '11'
523            );
524
525            $this->Cookie->write('searchData', $kidsCourseTeacher);
526        }
527
528        //NJ-9440 - add status ALL + Live flg
529        if (isset($this->request->query['from_live_lesson_usage']) && $this->request->query['from_live_lesson_usage'] == 1) {
530            $liveTeachers = array(
531                'sortRadio' => 'status',
532                'statusRadio' => 'all',
533                'searchLiveLesson' => '1'
534            );
535            $this->Cookie->write('searchData', $liveTeachers);
536        }
537
538        if (!class_exists('myMemcached')) {
539            App::uses('myMemcached', 'Lib');
540        }
541        $memcache = new myMemcached();
542        if ($this->Auth->loggedIn()) {
543            $memKey = "searchCallanUsers_{$this->sharedUserData['User']['id']}";
544        } else {
545            $memKey = "searchCallanUsers";
546        }
547        if ($memSearchReserveData = $memcache->get($memKey)) {
548            $this->Cookie->write('searchData', $memSearchReserveData);
549            $memcache->delete($memKey);
550        }
551
552        // NJ-5836
553        $displayRestrictionParams = array(
554            'lang' => $this->localizeDir
555        );
556
557        // get display restriction setting
558        $displayRestriction = $this->TextbookCategory->getDisplayRestrictionSettings($displayRestrictionParams);
559
560        $query = array();
561        if ($this->isStudySapuriUser) {
562            // Get all Book
563            $getAllBookArr = array(
564                'user_id' => $this->Auth->user('id'),
565                'textbook_type' => 2,
566                'arrange_data' => 'trunk',
567                'preset' => 'off',
568                'user_locale' => $this->localizeDir,
569                'load_description' => false
570            );
571            $seriesCategoryData = $this->Textbook->getTextbooks($getAllBookArr);
572            $seriesArr = $seriesCategoryData['res_data'];
573
574            $getSeriesPresetArr = array(
575                'user_id' => $this->Auth->user('id'),
576                'textbook_type' => 2,
577                'select_method' => 'first',
578                'preset' => 'off',
579                'displayRestriction' => $displayRestriction
580            );
581            $seriesPresetData = $this->Textbook->getTextbooks($getSeriesPresetArr);
582            $seriesPreset = $seriesPresetData['res_data'];
583            $seriesId = $seriesPreset['TextbookCategory']['id'];
584            // NC-7228 set series id from saved search condition
585            $searchData = $this->Cookie->read('searchData');
586            if(isset($searchData['seriesOptionSearchTextBookCategoryId']) && !empty($searchData['seriesOptionSearchTextBookCategoryId'])){
587                $seriesId = $searchData['seriesOptionSearchTextBookCategoryId'];
588            }
589            $seriesSelected = isset($seriesArr[$seriesId]) ? $seriesArr[$seriesId] : 0;
590
591            if ($seriesSelected) {
592                $query['badgeIds'] = $seriesSelected;
593            }
594
595            $this->set('seriesSpecialArr', $seriesArr);
596            $this->set('seriesSelected', $seriesSelected);
597        }
598        // - NJ-6390
599        $searchParams = !empty($query) && $query? $query : $this->Cookie->read('searchData');
600        $highLightFlag = null;
601        if (isset($searchParams['keywordText']) && $searchParams['keywordText']) {
602            // - 1 = able to highlight the keyWord freeword search
603            $highLightFlag = 1;
604
605            // -delete session
606            $this->Session->delete('freeword-'.$this->Auth->user('id'));
607
608            // - add session for freewordArray
609            $this->Session->write('freeword-'.$this->Auth->user('id'), $this->request->data['keywordText']);
610        }
611
612        $data = [];
613
614        if (!$this->isStudySapuriUser) {
615            $counselor = $this->Teacher->find('first', array(
616                'fields' => array(
617                    'Teacher.name',
618                    'Teacher.jp_name',
619                    'Teacher.image_url',
620                    'CountryCode.country_name'
621                ),
622                'joins' => array(
623                    array(
624                        'type' => 'LEFT',
625                        'table' => 'country_codes',
626                        'alias' => 'CountryCode',
627                        'conditions' => 'Teacher.homeland2 = CountryCode.id'
628                    )
629                ),
630                'conditions' => array('Teacher.id' => Configure::read('default_counselor_detail')),
631                'recursive' => -1
632            ));
633        }
634
635        # check counselor if hidden
636        $where = array(
637            'user_id' => $this->Auth->user('id'),
638            'teacher_id' => Configure::read('default_counselor_detail')
639        );
640        $isHide = $this->BlockList->isTeacherHide($where);
641        $this->set('isHide', $isHide);
642
643        $favId = $this->Auth->loggedIn() ? $this->UsersFavorite->getTeacherIdList($this->Auth->user('id')) : array();
644//        NJ-10550
645        $teacherFavs = $this->Auth->loggedIn() ?
646            $this->UsersFavoriteCategoriesTeacher->getColorFavTeacherByIds(['user_id' => $this->Auth->user('id'), 'teacher_ids' => array_values($favId)]) : [];
647        $colors = $this->UsersFavoriteCategoriesTeacher::COLORS;
648        $teacherFavsColors = []; //default
649
650        //-validate array variable
651        if (
652            $teacherFavs && 
653            is_array($teacherFavs)
654        ) {
655            $teacherFavsColors = array_map(function ($val) use ($colors) {
656                $index = array_search($val, array_column($colors, 'code'));
657                return $index >= 0 ? $colors[$index]['hex'] : '#F0295D';
658            }, $teacherFavs);
659        }
660
661        $this->set('teacherFavsColors', $teacherFavsColors);
662        // NC-7031 - avatar teachers
663        $avatarIdArr = array();
664        $teddyFav = false;
665        $getAvatarId = $this->Teacher->getParentAvatarTeacher();
666        if ($getAvatarId) {
667            $avatarIdArr = array_values($getAvatarId);
668
669            if ( $this->Auth->loggedIn() ) { // logged in
670                if ( $favId ) {
671                    // teddy
672                    $favAvaTParams = array(
673                        "avatar_id" => Configure::read('avatar_id.teddy'),
674                        "teacher_id" => $favId,
675                    );
676                    $checkTeddyFav = $this->Teacher->checkFavAvatarTeacher($favAvaTParams);
677
678                    if ($checkTeddyFav) {
679                        $teddyFav = true;
680                    }
681                }
682            }
683        }
684        //NC-9215 get teacher occupation industry and position
685        $this->set('occupationData', ClassRegistry::init('TeacherOccupationDetail')->getActiveOccupation());
686
687        // NJ-20272 : get counselor teacher lamp status
688        $counselorLampStatus = $this->Teacher->getCounselorLampStatus();
689
690        // NJ-9489 : check if membership is allowed to display counselor information
691         $_userData = $this->sharedUserData;
692        $hideCouselorFromMember = 0;
693        $n_isLitePlanUser = false;
694        if ($_userData) {
695            $_userPaymentPlan = $_userData['User']['payment_plan_id'];
696  
697            if (
698                  !$_userPaymentPlan ||
699                  in_array($_userPaymentPlan,Configure::read('counselor.not_allowed_payment_plan_id'))
700            ) {
701                $hideCouselorFromMember = 1;
702            }
703
704            // NJ-37250 : set lite plan user flag 
705            if ($_userPaymentPlan && in_array($_userPaymentPlan, Configure::read('lite_payment_plans'))) {
706                $n_isLitePlanUser = true;
707            }
708        
709        }
710        $this->set('is_lite_plan_user',$n_isLitePlanUser);
711        $this->set('hideCouselorFromMember',$hideCouselorFromMember);
712
713        $view->set(array(
714            'teddyFav' => $teddyFav,
715            'avatarActiveId' => $avatarIdArr,
716            'counselor' => isset($counselor) ? $counselor : null,
717            'teachers' => isset($data['teacherData']) ? $data['teacherData'] : array(),
718            'counterData' => isset($data['limitGauge']) ? $data['limitGauge'] : 0,
719            'teacherRecordCount' => isset($data['teacherRecordCount']) ? $data['teacherRecordCount'] : 0,
720            'recordCount' => isset($data['teacherData']) ? count($data['teacherData']) : 0,
721            'limitRecord' => isset($data['limit']) ? $data['limit'] : 0,
722            'estimateRecord' => isset($data['limit']) && isset($data['teacherData']) ? count($data['teacherData']) * $data['limit'] : 0, 
723            'messageFlag' => false,
724            'isLoggedIn' => $this->Auth->loggedIn(),
725            'caller' => 'waiting',
726            'favId' => $favId,
727            'userId' => $this->Auth->loggedIn() ? $this->sharedUserData['User']['id'] : '',
728            'isHide' => $isHide,
729            'highLightFlag' => $highLightFlag,
730            'counselorLampStatus' => $counselorLampStatus
731        ));
732        $teacherList = $view->render('/MyPage/online_teachers');
733        $this->set('teacherList', $teacherList);
734
735
736        // NC-9142
737        $badges = $this->Textbook->getPresetTextbookSeriesId();
738
739        $userLangId = $this->CountryCode->getUserLanguageId(!empty($_userData['User']['native_language2']) ? $_userData['User']['native_language2'] : Configure::read('english_language'));
740
741        // - get regions list
742        $this->set('regions', $this->Teacher->getAvailableNationality($this->localizeDir, ($this->isStudySapuriUser ? true : false), ($this->isStudySapuriUser ? $badges : '')), array(), $userLangId); //nationalities of teachers
743        
744        $this->set('coinData', $this->TeacherRankCoin->getCoinAmount()); // set coin dropdown
745        $defaultSearchData = $this->Cookie->read('searchData');
746
747        if (isset($this->request->query['campaign_filter']) && $this->request->query['campaign_filter']) {
748            $campaignFilter = $this->request->query['campaign_filter'];
749            $defaultSearchData['statusRadio'] = 'all';
750            $defaultSearchData['textbookRadioVal'] = 2;
751            $this->Cookie->write('searchReserveData.seriesOptionSearchTextBookCategoryId', Configure::read('campaign_config.'.$campaignFilter.'.ENV.'.Configure::read('ENVIRONMENT').'.textbook_category_id'));
752        }
753        $this->set('searchData', $defaultSearchData);
754        $this->set('isLogin', $this->Auth->loggedIn());
755
756        // NC-7228 get stored search conditions
757        $savedConditionsCount = $this->UserSearchCondition->getSavedConditionsCount($this->sharedUserData['User']['id'], $n_isLitePlanUser);
758        $this->set('savedConditionsCount', $savedConditionsCount);
759
760        // set default preset params
761        $presetParams = array(
762            'user_id' => $this->Auth->user('id'),
763            'lang' => (isset($this->localizeDir) && $this->localizeDir) ? $this->localizeDir : Configure::read('default.user_language'),
764            'is_pc_flg' => 1
765        );
766
767        //
768        if ((isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')) && 
769            ($this->Auth->loggedIn() && $this->Auth->user('currency_code') == Configure::read('default.user_currency'))
770          ){
771            $presetParams['userValidForSSBEDT'] = true;
772        }
773
774        //
775        if (isset($this->sharedUserData['User'])) {
776            //
777            $userDataObj = new UserTable($this->sharedUserData['User']);
778
779            //
780            if (!empty($userDataObj->getMembershipTypeIndex())) {
781                $presetParams["userMembershipType"] = $userDataObj->getMembershipTypeIndex();
782            }
783
784            $presetParams['native_language2'] = $userDataObj->native_language2;
785
786        }
787
788        // get preset data
789        $preset_data = $this->UsersTextbookInfo->getPreset($presetParams);
790
791        //
792        if(isset($preset_data['preset_connect_id']) && !empty($preset_data['preset_connect_id'])) {
793            // for preset
794            $presetParams['connect_id'] = $preset_data['preset_connect_id'];
795            $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
796
797        } else if(isset($preset_data['last_viewed_connect_id']) && !empty($preset_data['last_viewed_connect_id'])) {
798            // use last viewed textbook if no preset data.
799            $presetParams['connect_id'] = $preset_data['last_viewed_connect_id'];
800            $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
801
802        }
803
804        // initial fetch preset 
805        $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
806
807        // if no preset fetched - unsupported, fetch for tb with sort prioty 1
808        if(!$preset) {
809            unset($presetParams['connect_id']);
810            unset($presetParams['last_opened_date']);
811            $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
812        }
813
814        $this->set('preset', $preset);
815        $this->set('searchCondition', $this->Session->read('savedSearchCondition'));
816        //- 
817        $this->set('featureFilter', $this->FeatureRatingItem->getFeatureFilters(['langId' => $this->CountryCode->getUserLanguageId($this->localizeDir)]));
818
819        // - NJ-11223 
820        $oUserData = new UserTable($this->sharedUserData['User']);
821        $this->set('user', $oUserData);
822        $this->Session->delete('savedSearchCondition');
823
824        // NJ-21309
825        $memcached = new myMemcached();
826        $disconnectionChatHash = $memcached->get('disconnectionChatHash');
827        $this->set('disconnectionChatHash', $disconnectionChatHash);
828
829
830        //- NJ-36852
831        $this->ReservationCoin->openDBReplica();
832        $coins = $this->ReservationCoin->find('all', ['conditions'=> array('status' => 1)]);
833        $this->ReservationCoin->closeDBReplica();
834
835          $coinArray = [];
836        if($coins && is_array($coins)) {
837            foreach ($coins as $c) {
838                $coinArray[] = $c['ReservationCoin']['coin'];
839            }
840        } 
841        
842        $this->set("coins", json_encode($coinArray));
843
844        # NJ-19429: Search Campaign Teachers
845        $campaignTagSearch = $this->CampaignTagControl->getCampaignTagStatusPC($this->sharedUserData['User']['id']);
846        $this->set('campaignTagSearch', $campaignTagSearch);
847        
848    }
849
850    private function checkProperProfile($teacherId) {
851        if (!is_numeric($teacherId)) {
852            $this->redirect('/waiting/detail/'.intval($teacherId), '301');
853        } else if (!ctype_digit($teacherId)){
854            $this->log("Invalid [teacher_id] ".$teacherId, "error");
855            throw new NotFoundException();
856        }
857
858        /* commented conflict to localization
859        if (isset($this->params->url) && $this->params->url != 'waiting/detail/'.$teacherId) {
860            $this->redirect('/waiting/detail/'.$teacherId, '301');
861        }*/
862    }
863
864    /**
865     * @api {get} /user/:language/waiting/detail/:teacherId/:highLightFlag detail()
866     * @apiName detail
867     * @apiGroup Waiting
868     * @apiDescription Retrieves the detailed information for a specific teacher in Native Camp. It returns various information about the teacher, including lesson history, reviews, and more.
869     *
870     * @apiParam {String} language The language code.
871     * @apiParam {String} teacherId The ID of the teacher.
872     * @apiParam {String} [highLightFlag] The highlight flag.
873     * 
874     * @apiSuccess {Object} teacher The teacher object.
875     * @apiSuccess {String} teacher.id The ID of the teacher.
876     * @apiSuccess {String} teacher.name The name of the teacher.
877     * @apiSuccess {String} teacher.image The image URL of the teacher.
878     * @apiSuccess {Object} country The country object.
879     * @apiSuccess {String} country.name The name of the country.
880     * @apiSuccess {String} country.code The code of the country.
881     * @apiSuccess {Object} timezone The timezone object.
882     * @apiSuccess {String} timezone.name The name of the timezone.
883     * @apiSuccess {String} timezone.offset The offset of the timezone.
884     * @apiSuccess {Object} tutorCategory The tutor category object.
885     * @apiSuccess {String} tutorCategory.name The name of the tutor category.
886     * @apiSuccess {Number} timeDiff The time difference in seconds.
887     * @apiSuccess {Object} onair The on-air data.
888     * @apiSuccess {String} onair.id The ID of the on-air data.
889     * @apiSuccess {String} onair.status The status of the on-air data.
890     * @apiSuccess {String} userId The ID of the user.
891     * @apiSuccess {Object[]} series The list of textbook series.
892     * @apiSuccess {String} series.id The ID of the series.
893     * @apiSuccess {String} series.name The name of the series.
894     * @apiSuccess {Object[]} teacherTbRatings The teacher textbook ratings.
895     * @apiSuccess {String} teacherTbRatings.id The ID of the rating.
896     * @apiSuccess {String} teacherTbRatings.rating The rating value.
897     * @apiSuccess {Number} historyYear The number of years of teaching history.
898     * @apiSuccess {Number} historyMonth The number of months of teaching history.
899     * @apiSuccess {Object} teacherStatus1 The teacher status object.
900     * @apiSuccess {String} teacherStatus1.status The status of the teacher.
901     * @apiSuccess {Object} oOnair The on-air object.
902     * @apiSuccess {String} oOnair.id The ID of the on-air object.
903     * @apiSuccess {String} oOnair.status The status of the on-air object.
904     * @apiSuccess {Number} teacherTitleThreshold The teacher title threshold.
905     * @apiSuccess {Number} initialTeacherStatus The initial teacher status.
906     * @apiSuccess {Boolean} isFav Indicates if the teacher is favorited by the user.
907     * @apiSuccess {Boolean} isHide Indicates if the teacher is hidden by the user.
908     * @apiSuccess {Boolean} unsupportedBrowser Indicates if the browser is unsupported.
909     * @apiSuccess {Boolean} canReport Indicates if the user can report the teacher.
910     * @apiSuccess {Boolean} hideLimitedPlanReservation Indicates if the limited plan reservations should be hidden.
911     * @apiSuccess {Boolean} firstTimeLoggedIn Indicates if it is the user's first time logging in.
912     * @apiSuccess {Boolean} paidParent Indicates if the user is a paid parent.
913     * @apiSuccess {Number} velifyCount The count of phone verification logs.
914     * @apiSuccess {Object[]} countryCodes The list of country codes.
915     * @apiSuccess {String} countryCodes.code The code of the country.
916     * @apiSuccess {String} countryCodes.name The name of the country.
917     * @apiSuccess {Object} userCountry The user's country information.
918     * @apiSuccess {String} userCountry.name The name of the user's country.
919     * @apiSuccess {String} userCountry.code The code of the user's country.
920     * @apiSuccess {Boolean} deviceNotSupported Indicates if the device is not supported.
921     * @apiSuccess {Object} userLang The user's language information.
922     * @apiSuccess {String} userLang.name The name of the user's language.
923     * @apiSuccess {String} userLang.code The code of the user's language.
924     * @apiSuccess {Object} getCRData The country residence data.
925     * @apiSuccess {String} getCRData.country The country of residence.
926     * @apiSuccess {Object} residenceData The residence data.
927     * @apiSuccess {String} residenceData.city The city of residence.
928     * @apiSuccess {Boolean} residenceFlg Indicates if the residence flag is set.
929     * @apiSuccess {Boolean} login Indicates if the user is logged in.
930     * @apiSuccess {Object} preset The preset textbook information.
931     * @apiSuccess {String} preset.id The ID of the preset textbook.
932     * @apiSuccess {String} preset.name The name of the preset textbook.
933     * @apiSuccess {Boolean} presetIsLiveTextbook Indicates if the preset textbook is for live lessons.
934     * @apiSuccess {Object[]} apologyList The list of apologies.
935     * @apiSuccess {String} apologyList.id The ID of the apology.
936     * @apiSuccess {String} apologyList.message The message of the apology.
937     * @apiSuccess {Boolean} isNormalLitePlanUser Indicates if the user is on a normal lite plan.
938     * @apiSuccess {Object} getKeepMemo The keep memo information.
939     * @apiSuccess {String} getKeepMemo.id The ID of the keep memo.
940     * @apiSuccess {String} getKeepMemo.memo The memo text.
941     * @apiSuccess {String} textbookConnectId The textbook connect ID.
942     * @apiSuccess {Number} textbookCategoryTypeId The textbook category type ID.
943     * @apiSuccess {Boolean} highLightFlag Indicates if the highlight flag is set.
944     * @apiSuccess {Number} liveCoin The live lesson coin amount.
945     * @apiSuccess {Number} order The order of the teacher reviews.
946     * @apiSuccess {Object[]} lesson_history_data The lesson history data.
947     * @apiSuccess {String} lesson_history_data.id The ID of the lesson history.
948     * @apiSuccess {String} lesson_history_data.date The date of the lesson history.
949     * @apiSuccess {Boolean} showRating Indicates if the rating should be shown.
950     * @apiSuccess {Object} reserveAndCancel The reservation and cancellation data.
951     * @apiSuccess {Number} reserveAndCancel.reserved The number of reserved lessons.
952     * @apiSuccess {Number} reserveAndCancel.cancelled The number of cancelled lessons.
953     * @apiSuccess {Number} lessonHistoryCount The count of lesson history.
954     * @apiSuccess {Object} latestUserLesson The latest user lesson information.
955     * @apiSuccess {String} latestUserLesson.id The ID of the latest user lesson.
956     * @apiSuccess {String} latestUserLesson.date The date of the latest user lesson.
957     * @apiSuccess {Object} teacherRates The teacher rates.
958     * @apiSuccess {Number} teacherRates.rate The rate of the teacher.
959     * @apiSuccess {String} teacherIdCheck The teacher ID check.
960     * @apiSuccess {String} latestLessonData The latest lesson data.
961     * @apiSuccess {String} teacherLastLogin The last login time of the teacher.
962     * @apiSuccess {Number} teacherFavoriteCount The favorite count of the teacher.
963     * @apiSuccess {Object} teacherFeatures The teacher features.
964     * @apiSuccess {String} teacherFeatures.feature The feature of the teacher.
965     * @apiSuccess {Boolean} validCampaignDate Indicates if the campaign date is valid.
966     * @apiSuccess {Object} campaign The campaign information.
967     * @apiSuccess {String} campaign.id The ID of the campaign.
968     * @apiSuccess {String} campaign.name The name of the campaign.
969     * @apiSuccess {Object[]} ownReservationTeacherData The own reservation teacher data.
970     * @apiSuccess {String} ownReservationTeacherData.id The ID of the reservation.
971     * @apiSuccess {String} ownReservationTeacherData.date The date of the reservation.
972     * @apiSuccess {Number} studentDelayInSeconds The delay in seconds for the student lesson priority.
973     * @apiSuccess {Number} remainingSeconds The remaining seconds for the lesson.
974     * @apiSuccess {Boolean} ownReservationFlg Indicates if the user has their own reservation.
975     * @apiSuccess {String} teacherStatusColor The color of the teacher status.
976     * @apiSuccess {String} chatHash The chat hash.
977     * @apiSuccess {Boolean} liveLessonFlg Indicates if the lesson is a live lesson.
978     * @apiSuccess {Number} lessonRequestFlg The lesson request flag.
979     *
980     * @apiSuccessExample {json} Success-Response:
981     *     {
982     *         "teacher": {
983     *             "id": "123",
984     *             "name": "John Doe",
985     *             "image": "http://example.com/image.jpg"
986     *         },
987     *         "country": {
988     *             "name": "Japan",
989     *             "code": "JP"
990     *         },
991     *         "timezone": {
992     *             "name": "JST",
993     *             "offset": "+09:00"
994     *         },
995     *         "tutorCategory": {
996     *             "name": "English"
997     *         },
998     *         "timeDiff": 0,
999     *         "onair": {
1000     *             "id": "456",
1001     *             "status": "active"
1002     *         },
1003     *         "userId": "123",
1004     *         "series": [
1005     *             {
1006     *                 "id": "1",
1007     *                 "name": "Series 1"
1008     *             }
1009     *         ],
1010     *         "teacherTbRatings": [
1011     *             {
1012     *                 "id": "1",
1013     *                 "rating": "5"
1014     *             }
1015     *         ],
1016     *         "historyYear": 2,
1017     *         "historyMonth": 6,
1018     *         "teacherStatus1": {
1019     *             "status": "available"
1020     *         },
1021     *         "oOnair": {
1022     *             "id": "789",
1023     *             "status": "active"
1024     *         },
1025     *         "teacherTitleThreshold": 0,
1026     *         "initialTeacherStatus": 1,
1027     *         "isFav": true,
1028     *         "isHide": false,
1029     *         "unsupportedBrowser": false,
1030     *         "canReport": true,
1031     *         "hideLimitedPlanReservation": false,
1032     *         "firstTimeLoggedIn": false,
1033     *         "paidParent": false,
1034     *         "velifyCount": 1,
1035     *         "countryCodes": [
1036     *             {
1037     *                 "code": "JP",
1038     *                 "name": "Japan"
1039     *             }
1040     *         ],
1041     *         "userCountry": {
1042     *             "name": "Japan",
1043     *             "code": "JP"
1044     *         },
1045     *         "deviceNotSupported": false,
1046     *         "userLang": {
1047     *             "name": "Japanese",
1048     *             "code": "ja"
1049     *         },
1050     *         "getCRData": {
1051     *             "country": "Japan"
1052     *         },
1053     *         "residenceData": {
1054     *             "city": "Tokyo"
1055     *         },
1056     *         "residenceFlg": true,
1057     *         "login": true,
1058     *         "preset": {
1059     *             "id": "1",
1060     *             "name": "Preset Textbook"
1061     *         },
1062     *         "presetIsLiveTextbook": true,
1063     *         "apologyList": [],
1064     *         "isNormalLitePlanUser": true,
1065     *         "getKeepMemo": {
1066     *             "id": "1",
1067     *             "memo": "This is a memo."
1068     *         },
1069     *         "textbookConnectId": "123",
1070     *         "textbookCategoryTypeId": 1,
1071     *         "highLightFlag": true,
1072     *         "liveCoin": 100,
1073     *         "order": 0,
1074     *         "lesson_history_data": [
1075     *             {
1076     *                 "id": "1",
1077     *                 "date": "2023-12-01"
1078     *             }
1079     *         ],
1080     *         "showRating": true,
1081     *         "reserveAndCancel": {
1082     *             "reserved": 10,
1083     *             "cancelled": 2
1084     *         },
1085     *         "lessonHistoryCount": 10,
1086     *         "latestUserLesson": {
1087     *             "id": "1",
1088     *             "date": "2023-12-01"
1089     *         },
1090     *         "teacherRates": {
1091     *             "rate": 5
1092     *         },
1093     *         "teacherIdCheck": "123",
1094     *         "latestLessonData": "2023-12-01 (Fri)",
1095     *         "teacherLastLogin": "01/12/2023 (Fri)",
1096     *         "teacherFavoriteCount": 50,
1097     *         "teacherFeatures": {
1098     *             "feature": "Friendly"
1099     *         },
1100     *         "validCampaignDate": true,
1101     *         "campaign": {
1102     *             "id": "1",
1103     *             "name": "Campaign 1"
1104     *         },
1105     *         "ownReservationTeacherData": [
1106     *             {
1107     *                 "id": "1",
1108     *                 "date": "2023-12-01"
1109     *             }
1110     *         ],
1111     *         "studentDelayInSeconds": 0,
1112     *         "remainingSeconds": 0,
1113     *         "ownReservationFlg": true,
1114     *         "teacherStatusColor": "green",
1115     *         "chatHash": "abc123",
1116     *         "liveLessonFlg": true,
1117     *         "lessonRequestFlg": 1
1118     *     }
1119     *
1120     * @apiError {String} status The status of the request (NG).
1121     * @apiError {String} message The error message.
1122     *
1123     * @apiErrorExample {json} Error-Response:
1124     *     {
1125     *         "status": "NG",
1126     *         "message": "Invalid request."
1127     *     }
1128     * 
1129     * @apiSampleRequest off
1130     */
1131    public function detail($teacherId = null, $highLightFlag = null) {
1132
1133        if (is_null($teacherId)) {
1134            return $this->redirect(myTools::getUrl() . '/user/waiting', 301);
1135        }
1136
1137        if (isset($this->request->query['emergency']) && !$this->isStudySapuriTosUser) {
1138            return $this->redirect(myTools::getUrl() . '/waiting');
1139        }
1140
1141        //set mobile view
1142        if (myTools::defaultAction($this) || (isset($_GET['classViewTeacher']) && $_GET['classViewTeacher'] == 1)) {
1143            return $this->spDetail($teacherId);
1144        }
1145        $counselorParams = array(
1146            'type' => 'count',
1147            'args' => array(
1148                'conditions' => array(
1149                    'id' => $teacherId,
1150                    'counseling_flg' => 1
1151                ),
1152                'recursive' => -1
1153            )
1154        );
1155
1156        // - NC-3802: redirect to mypage if counselor teacher
1157        if ($this->Teacher->getTeachers($counselorParams)) {
1158            return $this->redirect('/mypage');
1159        }
1160
1161        $customer_support_flg = $this->TeacherDetail->isCustomerSupportTeacher($teacherId);
1162        //NJ-36255 - redirect to  customer support page if customer support teacher
1163        if($customer_support_flg){
1164            return $this->redirect('/customersupport_detail');
1165        }
1166        
1167        //NJ-65055: params for checking teacher is hidden
1168        $isTeacherHiddenParams = array(
1169            'user_id' => $this->Auth->user('id'),
1170            'teacher_id' => $teacherId
1171        );
1172
1173        if ((BlockListTable::isUserBlocked($this->Auth->User('id'), $teacherId) == true) || $this->BlockList->isTeacherHide($isTeacherHiddenParams)) {
1174            return $this->redirect('/waiting');
1175        }
1176
1177        // - NC-7031: redirect avatar
1178        $avatarData = $this->isAvatar($teacherId);
1179        if ($avatarData) {
1180            $getAId = $avatarData;
1181            return $this->redirect('/avatar_detail/'.$getAId);
1182        }
1183
1184        //redirect to proper profile
1185        $this->checkProperProfile($teacherId);
1186
1187        $this->Teacher->unbindModel(array('hasOne' => array('LessonOnair')));
1188        $queryCondition = array(
1189            'fields' => array(
1190                    'TeacherRankCoin.coins',
1191                    'TeacherRankCoin.reserve_coin_settings_flg',
1192                    'LessonOnair.id',
1193                    'LessonOnair.teacher_id',
1194                    'LessonOnair.user_id',
1195                    'TeacherRankCoin.limited_plan_reservation'
1196                ),
1197            'joins' => array(
1198                array(
1199                    'type' => 'LEFT',
1200                    'table' => 'teacher_rank_coins',
1201                    'alias' => 'TeacherRankCoin',
1202                    'conditions' => array('Teacher.rank_coin_id = TeacherRankCoin.id AND TeacherRankCoin.status')
1203                )
1204            ),
1205            'conditions' => array(
1206                array('Teacher.id' => $teacherId)
1207            ),
1208            'show' => 'first'
1209        );
1210
1211        $commonTeacherStatusParams = array(
1212            'page_display' => 'listTeacher',
1213            'query_conditions' => $queryCondition
1214        );
1215        $data = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
1216
1217        if (!$data) {
1218            return $this->redirect('/waiting/');
1219        }
1220
1221        if (in_array($data['Teacher']['rank_coin_id'], $this->blockMemberSettings)) {
1222            return $this->redirect('/mypage');
1223        }
1224        // NJ-51 : Set delay for student lesson priority group
1225        $studentDelayInSeconds = 0;
1226        $standbyStatus = false;
1227        $remainingSeconds = 0;
1228        $chatHash = $this->request->query('chatHash') ?? null;
1229
1230        if( isset($data['LessonOnair']) && $data['LessonOnair'] ) {
1231            $loAir = $data['LessonOnair'];
1232            if( (isset($loAir['status']) && $loAir['status'] == 1) ) {
1233                $standbyStatus = true;
1234            }
1235        }
1236
1237        if( isset($data['TeacherStatus']) && $data['TeacherStatus'] && $data['TeacherStatus']['teacher_status'] == 2 ) {
1238            $tstatus = $data['TeacherStatus'];
1239            if( isset($tstatus['created']) && $tstatus['created'] ) {
1240                if( isset($data[0]['teacher_status_standby_duration']) && $data[0]['teacher_status_standby_duration'] ) {
1241                    if( (int)$data[0]['teacher_status_standby_duration'] <= (int)$this->studentLessonPriorityTimeDelayInSeconds ) {
1242                        $remainingSeconds = (int)$this->studentLessonPriorityTimeDelayInSeconds - (int)$data[0]['teacher_status_standby_duration'];
1243                    }
1244                }
1245                $studentDelayInSeconds = (int) $remainingSeconds * 1000;
1246            }
1247        }
1248
1249        //- check lesson type
1250        $liveLessonFlg = isset($data['LessonOnair']['live_lesson_flg']) ? $data['LessonOnair']['live_lesson_flg'] : 0;
1251
1252        //-get userid
1253        $userId = isset($this->sharedUserData['User']['id']) ? $this->sharedUserData['User']['id'] : $this->Auth->user('id');
1254
1255        $ownReservationFlg = 0;
1256        if ( $userId ) {
1257            $teacherStatusColor = '';
1258            $teacherObj = new TeacherTable($data['Teacher']);
1259            $tsObj = new TeacherStatusTable($data['TeacherStatus']);
1260
1261            // get reservation
1262            $nextReservation = LessonScheduleTable::getReservation(array(
1263                'LessonSchedule.teacher_id' => $teacherObj->id,
1264                'LessonSchedule.user_id' => $userId
1265            ));
1266        
1267
1268            //-- if user cannot use live lesson -> force to disabled live lesson flag
1269            if ( isset($data['LessonOnair']['live_lesson_flg']) && empty($allowLiveLesson) ) {
1270                $data['LessonOnair']['live_lesson_flg'] = 0;
1271            }
1272
1273            $loStatusParams = array(
1274                'LessonOnair' => $data['LessonOnair'],
1275                'Teacher' => $data['Teacher'],
1276                'TeacherStatus' => $tsObj,
1277                'nextReservation' => isset($nextReservation['teacher_id']) ? $nextReservation['teacher_id'] : null,
1278                'userId' => $userId
1279            );
1280            $teacherStatus = LessonOnairTable::teacherStatusColor($loStatusParams);
1281            $teacherStatusColor = TeacherTable::teacherStatusCSS($teacherStatus);
1282            if( $teacherStatus == '5' ) {
1283                $ownReservationFlg = 1;
1284            }
1285
1286            // - user callan unli option flg
1287            $callan_option = isset($this->sharedUserData['User']['callan_option']) ? $this->sharedUserData['User']['callan_option'] : 0;
1288
1289            // - user native unli option flg
1290            $native_option = isset($this->sharedUserData['User']['native_option']) ? $this->sharedUserData['User']['native_option'] : 0;
1291
1292            $can_use_callan_option = 0;
1293            if($callan_option || $native_option) {
1294                $can_use_callan_option = 1;
1295            }
1296
1297            $this->set('can_use_callan_option', $can_use_callan_option);
1298
1299            // - teacher callan unli option flg
1300            $unlimited_option_flag = $this->HomeBasedRankBasicAmount->getUnlimitedOptionFlg($teacherObj->current_rank_id);
1301            $callan_option_teacher_flg = (isset($unlimited_option_flag['callan_unlimited_option_flg']) && $unlimited_option_flag['callan_unlimited_option_flg']) ? $unlimited_option_flag['callan_unlimited_option_flg'] : 0; 
1302            $this->set('callan_option_teacher_flg', $callan_option_teacher_flg);
1303            
1304            // - check if has callan badge
1305            $teacher_callan_badge = ClassRegistry::init('TeacherBadge')->checkCallanBadges(array('teacher_id' => $teacherId));
1306            $this->set('teacher_callan_badge', $teacher_callan_badge);
1307        }
1308
1309        //-default
1310        $liveStatus = 0;
1311
1312        //- fetch live waiting reservation
1313        $waitingReservationLive = [];
1314        if ($this->Auth->loggedIn() && $liveLessonFlg) {
1315            //- fetch user reservation
1316            $reservedLessonData = $this->LessonSchedule->getReservationLessonNow($userId);
1317
1318            if ($reservedLessonData && $reservedLessonData['Teacher']['id'] != $teacherId) {
1319                $liveStatus = 0;
1320            } else {
1321                //- if lesson started
1322                if (
1323                    !is_null($data['LessonOnair']['connect_id']) &&
1324                    !is_null($data['LessonOnair']['user_id'])
1325                ) {
1326                    if ($data['LessonOnair']['user_id'] == $userId) {
1327                        $liveStatus = 4;
1328                    } else {
1329                        //- check live status
1330                        $liveStatus = $this->LessonOnairsViewer->onGoingLiveStatus([
1331                            'user_id' => $userId,
1332                            'chat_hash' => $data['LessonOnair']['chat_hash']
1333                        ]);
1334
1335                        //-- override status to watch
1336                        if ($liveStatus == 1) {
1337                            $liveStatus = 2; //view live
1338                        }
1339                    }
1340                } else {
1341                    $waitingReservationLive = $this->LessonSchedule->getWaitingLiveReservation([
1342                        'teacher_id' => $teacherId
1343                    ]);
1344
1345                    //-has reservation
1346                    if ($waitingReservationLive) {
1347                        if ($waitingReservationLive['LessonSchedule']['user_id'] == $userId) {
1348                            $liveStatus = (date('i') >= 0 && date('i') <= 26) || (date('i') >= 30 && date('i') <= 56) ? 4 : 0;
1349                        } else {
1350                            $liveStatus = 1; //live will start
1351                        }
1352                    }
1353                }
1354            }
1355        }        
1356
1357        //redirect if withdrawn teacher
1358        if ($data['Teacher']['status'] <> 1 || $data['Teacher']['inactive_flg'] == 1) {
1359            if ($this->Auth->loggedIn()) {
1360                return $this->redirect(myTools::geturl() . '/mypage');
1361            } else {
1362                return $this->redirect(myTools::geturl() . '/waiting');
1363            }
1364        }
1365
1366        if (isset($data['LessonOnair'])) {
1367            $tmp = (object) $data['LessonOnair'];
1368            if (!$tmp->id) {
1369                $data['LessonOnair'] = null;
1370            }
1371        }
1372
1373        // get teacher information
1374        $teacher = new TeacherTable($data['Teacher']);
1375        $country = new TeacherTable($data['CountryCode']);
1376        $timezone = new TimezoneTable($data['Timezone']);
1377        $tutorCategory = new TeacherRankCoinTable($data['TeacherRankCoin']);
1378
1379        $timeDiff = 0;
1380        if (isset($timezone->continent_id) && isset($timezone->city_eng)) {
1381            $timeDiffData = $this->Timezone->computeTimeDiff(array(
1382                'continent_id' => $timezone->continent_id,
1383                'city' => $timezone->city_eng
1384            ));
1385
1386            //
1387            if ($timeDiffData['success']) {
1388                $timeDiff = $timeDiffData['timeDiff'];
1389            }
1390        }
1391
1392        $onair = $data['LessonOnair'];
1393        $onairDataArr = isset($data['LessonOnair']) && $data['LessonOnair'] ? $data['LessonOnair'] : array();
1394
1395        $userId = ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null;
1396
1397        $fieldArr = array(
1398            'TextbookCategory.name',
1399            'TextbookCategory.id',
1400            'TextbookCategory.type_id',
1401            'TeacherBadge.textbook_category_id',
1402            'TeacherBadge.badge_flg',
1403            'TextbookCategory.type_id',
1404            'TextbookCategory.image_big_url'
1405        );
1406        $joinArr = array(
1407            array(
1408                'table' => 'teacher_badges',
1409                'alias' => 'TeacherBadge',
1410                'type' => 'LEFT',
1411                'conditions' => array('TeacherBadge.textbook_category_id = TextbookCategory.id', 'TeacherBadge.teacher_id' => $teacherId)
1412            )
1413        );
1414
1415        // if the user's language is zh-tw, display chinese textbook badge name
1416        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))){
1417            $langId = ClassRegistry::init('CountryCode')->getUserLanguageId($this->localizeDir);
1418            if($langId){
1419                $joinArr[] = array(
1420                    'type' => 'LEFT',
1421                    'table' => 'global_textbook_categories',
1422                    'alias' => 'GlobalTextbookCategory',
1423                    'conditions' => array(
1424                        'GlobalTextbookCategory.language_id' => $langId,
1425                        'GlobalTextbookCategory.textbook_category_id = TextbookCategory.id'
1426                    )
1427                );
1428                $this->TextbookCategory->virtualFields = array(
1429                    'gl_name' => 'GlobalTextbookCategory.gl_name'
1430                );
1431                $fieldArr[] = 'gl_name';
1432            }
1433        }
1434
1435        $conArr = array(
1436            'TextbookCategory.status' => 1,
1437            'TextbookCategory.type_id' => 2
1438        );
1439
1440        # get studydapuri textbooks
1441        $studysapuriType = Configure::read('studysapuri_textbook_category_types');
1442        if ( $this->studySapuriId && isset($this->sharedUserData['User']['payment_plan_id']) ) {
1443            $plan = myTools::studySapuriContractPlan($this->sharedUserData['User']['payment_plan_id']);
1444            $conArr['TextbookCategory.textbook_category_type'] = $studysapuriType[$plan];
1445        } elseif ($this->isStudySapuriTosUser) {
1446            $conArr['TextbookCategory.textbook_category_type'] = Configure::read('stasapu_tos_textbook_category_type');
1447        } else {
1448            $exCat = Configure::read('all_sapuri_textbook_category_types');
1449            $conArr['NOT'] = array('TextbookCategory.textbook_category_type' => $exCat);
1450        }
1451
1452        //NJ-24096: get last reservation textbook type
1453        $reservationTextbookConnectId = "";
1454        if ($userId) {
1455            $sapuriFlg = ($this->isStudySapuriTosUser || $this->isStudySapuriUser) ? true : false;
1456            $lastReservationData = LessonScheduleTable::getLastReservation($this->Auth->user('id'), $sapuriFlg);
1457
1458            if (!empty($lastReservationData['LessonSchedule']['connect_id'])) {
1459                $reservationTextbookConnectId = $lastReservationData['LessonSchedule']['connect_id'];
1460            } else {
1461                $this->User->openDBReplica();
1462                $checkUserFirstFlg = $this->LessonSchedule->field('connect_id', array('user_id' => $userId));
1463                $this->User->closeDBReplica();
1464                if (empty($checkUserFirstFlg)) {
1465                    $defaultParams = array(
1466                        'user_id' => $userId,
1467                        'lang' => $userData->native_language2 ?? $this->localizeDir,
1468                    );
1469                    $defaultReservation = $this->Textbook->getDefaultReservationTBConnectId($defaultParams);
1470                    if ($defaultReservation) {
1471                        $reservationTextbookConnectId = $defaultReservation;
1472                    }
1473                }
1474            }
1475        }
1476        $this->set(compact('reservationTextbookConnectId'));
1477
1478        // NJ-5836
1479        $displayRestrictionParams = array(
1480            'lang' => $this->localizeDir
1481        );
1482
1483        // get display restriction setting
1484        $displayRestriction = $this->TextbookCategory->getDisplayRestrictionSettings($displayRestrictionParams);
1485
1486        // NJ-5836 add condition for display restriction
1487        if(isset($displayRestriction['field']) && $displayRestriction['field']){
1488            // set condition for display restriction
1489            $conArr['TextbookCategory.'.$displayRestriction['field']] = 1;
1490        }
1491
1492        //get series and badge
1493        $series = $this->TextbookCategory->find('all', array(
1494            'fields' => $fieldArr,
1495            'conditions' => $conArr,
1496            'joins' => $joinArr,
1497            'order' => array(
1498                'TextbookCategory.sort' => 'ASC'
1499            )
1500        ));
1501
1502        $this->set('series', $series);
1503        myTools::initializeApiTunnel(array('TeachersDetailController'));
1504        $teachersDetail = new TeachersDetailController();
1505
1506        $teacherTbRatings = array();
1507        
1508        if (isset($series) && is_array($series) && count($series) > 0) {
1509            foreach($series as $books){            
1510                $categoryId = $books['TextbookCategory']['id'];
1511                $params = array(
1512                    'teacher_id' =>  (int) $teacherId,
1513                    'textbook_category_id' => (int) $categoryId,
1514                    'nc_terminal_type' => Configure::read('nc_terminal_type.pc')
1515                );
1516                $teachersDetail->params = $params;        
1517                $decodeResp = json_decode($teachersDetail->teacherTextbookRating());
1518                $teacherTbRatings[$categoryId] = $decodeResp->teacher_textbook_rating;
1519            }
1520        }
1521
1522        $this->set('teacherTbRatings', $teacherTbRatings);
1523
1524        [$historyYear, $historyMonth] = $teacher->getTotalTeachingExperience();
1525
1526        $this->set('historyMonth',$historyMonth);
1527        $this->set('historyYear',$historyYear);
1528
1529        //teacher_status if login or break
1530        $teacherStatus1 = $this->TeacherStatus->find('first', array(
1531            'fields' => array('TeacherStatus.status', 'TeacherStatus.remarks1', 'TeacherStatus.remarks2'),
1532            'conditions' => array('TeacherStatus.teacher_id' => $teacher->getId())
1533        ));
1534
1535        //lesson onair
1536        if (!empty($onair)) {
1537            $oOnair = new LessonOnairTable($onair);
1538        } else {
1539
1540            if (!empty($teacherStatus1)) {
1541                $oOnair = new TeacherStatusTable($teacherStatus1['TeacherStatus']);
1542            } else {
1543                $oOnair = 0;
1544            }
1545        }
1546
1547        // NJ-17264
1548        $teacherTitleThreshold = 0;
1549        if(isset($data['TitleThresholdTeacher']['title_type'])){
1550            $teacherTitleThreshold = $data['TitleThresholdTeacher']['title_type'];
1551        }
1552
1553        // inital teacher status
1554        $initialTeacherStatus = isset($teacherStatus1['TeacherStatus']) && $teacherStatus1['TeacherStatus']['status'] ? $teacherStatus1['TeacherStatus']['status'] : 0;
1555
1556        //favorite
1557        $where = array(
1558            'UsersFavorite.user_id'     => $this->Auth->user('id'),
1559            'UsersFavorite.teacher_id'     => $teacherId,
1560        );
1561        $isFav = $this->UsersFavorite->find('count', array('conditions' => $where));
1562
1563        // NC-5897 : check if teacher was hide by user.
1564        $where = array(
1565            'user_id' => $this->Auth->user('id'),
1566            'teacher_id' => $teacherId,
1567        );
1568        $isHide = $this->BlockList->isTeacherHide($where);
1569        $this->User->recursive = -1;
1570        $data = $this->User->findById($userId);
1571        $user = isset($data['User'])?$data['User']: null;
1572        $unsupportedBrowser = false;
1573        $browser =  $this->request->header('User-Agent');
1574
1575        if (preg_match('/(Edg|Edge)/i',$browser) ) {
1576            $unsupportedBrowser = false;
1577        } elseif (!preg_match('/(Chrome|Firefox|Safari)/i',$browser)) {
1578            $unsupportedBrowser = true;
1579        }
1580        $canReport = true;
1581        if ($user) {
1582            $userData = new UserTable($data['User']);
1583            $userMembership = $userData->getUserMembership();
1584            $this->set('user_lang', $userData->native_language2);
1585            // if weekly plan user
1586            $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($userData->payment_plan_id);
1587            $corporateUser = isset($corporateType) ? $corporateType : '';
1588
1589            $userMemberTypeCantReportTeacher = Configure::read('user_member_type.cant_report_teacher');
1590            $canReport = $userData->getMembershipTypeIndex();
1591            $canReport = in_array($canReport, $userMemberTypeCantReportTeacher) ? false : true;
1592        }
1593        $this->set('unsupportedBrowser', $unsupportedBrowser);
1594        // NC-6615 check if user can report the teacher
1595        $this->set('canReport', $canReport);
1596
1597        $hideLimitedPlanReservation = false;
1598        if ($tutorCategory->limited_plan_reservation == 0 && (isset($corporateUser) && $corporateUser ==  Configure::read('corporate_type.limited'))) {
1599            $hideLimitedPlanReservation = true;
1600        }
1601
1602        $firstTimeLoggedIn = false;
1603        if (empty($user['last_login_time'])) {
1604            $firstTimeLoggedIn = true;
1605        }
1606
1607        $paidParent = false;
1608
1609        $velifyCount = $this->PhoneVerifyCheckLog->find('count',array(
1610            'conditions' => array(
1611                'user_id' => $this->Auth->user('id'),
1612                'status' => 0
1613            )
1614        ));
1615
1616        $countryCodes = $this->CountryCode->find('all',array(
1617            'fields' => array(
1618                'code',
1619                'country_name'
1620            ),
1621            'order' => 'country_name ASC'
1622        ));
1623        $this->set('countryCodes',$countryCodes);
1624
1625        $userCountry['CountryCode']['country_name'] = '';
1626        $userCountry['CountryCode']['code'] = '';
1627        if(!empty($data['User']['country_code'])){
1628            $userCountry = $this->CountryCode->find('first',array(
1629                'conditions' => array(
1630                    'code' => $data['User']['country_code']),
1631                'fields' => array(
1632                    'code',
1633                    'country_name')
1634            ));
1635            if(empty($userCountry)){
1636                $userCountry['CountryCode']['code'] = '';
1637            }
1638        }
1639        $this->set('countryCodes',$countryCodes);
1640
1641        //check if user is child by checking its parent id not empty
1642        if (isset($data['User']['parent_id'])) {
1643            $paidParent = $this->User->checkPaidParent($data['User']['parent_id']);
1644        }
1645        #$lesson_count=0;
1646        // 管理者権限会員は無制限でレッスン出来る
1647        if (isset($user['admin_flg']) && $user['admin_flg']=='1') {
1648            $user['charge_flg'] = 1;
1649            $lesson_count=0;
1650            $lesson_count_today = 0;
1651        }
1652
1653        if (empty($user['enquate6'])) {
1654            $user['enquate6'] = '1';
1655        }
1656
1657        if (empty($user['enquate7'])) {
1658            $user['enquate7'] = '1';
1659        }
1660
1661        // if tos user
1662        if (isset($this->sharedUserData['UsersExtend']['id'])) {
1663            $user['tos_user'] = true;
1664        }
1665
1666        //number of stusap lesson
1667        $stusapLessonCount = (int)$teacher->stusap_lesson_count + (int)$teacher->stasapu_tos_lesson_count;
1668        //number of lesson
1669        $lessonCount = (int)$teacher->lesson_count;
1670
1671        // - prepare head text
1672        $headTextWD = $pageTitleWD = $teacher->name;
1673        $metaDescWD = "";
1674        if ($this->localizeDir == Configure::read('default.user_language')) {
1675            $headTextWD .= '('.$teacher->jp_name.')';
1676            $pageTitleWD .=  '('.$teacher->jp_name.')';
1677            //$metaDescWD .= '('.$teacher->jp_name.')';
1678        }
1679
1680        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) { // if the language is Custom language format
1681            $headTextWD .= '&ensp;'. __d('waiting','レッスン数').': '.$lessonCount . ' ' . lcfirst(($lessonCount <= 1 ?  __dx('waiting', 'singular', '回') :  __d('waiting', '回'))); 
1682        } else { // if the language is not Custom language format
1683            $headTextWD .= '&ensp;'. __d('waiting','レッスン数').':'.$lessonCount. __d('waiting','回');
1684        }
1685        $pageTitleWD .= '&ensp;' . sprintf(__d('waiting', 'レッスン:%s回 - 講師詳細 | オンライン英会話のネイティブキャンプ'), $lessonCount);
1686        //$metaDescWD .= __d('waiting','講師の紹介ページです。').$teacher->getMetaDescription();
1687
1688        //prepare meta image 
1689        $_teacherImgUrl = $teacher->getImageUrl();
1690
1691        //check if teacher has no image 
1692        if (empty($teacher->image_url) || !$teacher->image_url) {
1693            $defaultTeacherImg = myTools::getUrl() . '/teacher/img/no_profile_img.jpg';
1694            $_teacherImgUrl = ($_teacherImgUrl == $defaultTeacherImg) ? $_teacherImgUrl : $defaultTeacherImg;
1695        }
1696
1697
1698        // - set page meta information
1699        $this->set('headtext', $headTextWD);
1700        $this->set('title_for_layout', $pageTitleWD);
1701        // $this->set('meta_description', $metaDescWD);
1702        $this->set('meta_keywords',$teacher->name.',講師,オンライン英会話,ネイティブキャンプ');
1703        $this->set('counselingFlg',$teacher->counseling_flg);
1704        $this->set('meta_teacher_img',$_teacherImgUrl);
1705
1706        $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir);
1707        $options['language_id'] = $reviewLanguage[0] ?? null;
1708        $options['not_language_ids'] = $reviewLanguage[1] ?? null;
1709
1710        $userTable = new UserTable($this->Auth->user());
1711        $sapuriPlan = $userTable->isStudySapuri();
1712        $sapuriTextbookType = Configure::read('all_sapuri_textbook_category_types');
1713        if ($this->isStudySapuriUser && isset($sapuriTextbookType[$sapuriPlan])) {
1714            $options['textbook_category_type'] = $sapuriTextbookType[$sapuriPlan];
1715        } else {
1716            $options['textbook_category_type_not_in'] = $sapuriTextbookType;
1717        }
1718        $commentCount = $this->UsersClassEvaluation->getCommentCount($teacherId , $options);
1719        $approveFlag = $this->UsersClassEvaluation->getApproveEvalCount($teacherId);
1720
1721        $get_weekly_rating = $this->UsersClassEvaluation->getRatings($teacherId,true);
1722        $get_weekly_rating['TeacherWeeklyRating']['averageRate'] ??= '';
1723        if ($get_weekly_rating['TeacherWeeklyRating']['averageRate']) {
1724            if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) {
1725                $get_weekly_rating['TeacherWeeklyRating']['ratings'] = number_format($get_weekly_rating['TeacherWeeklyRating']['averageRate'], 2, ',', '');
1726            } else {
1727                $get_weekly_rating['TeacherWeeklyRating']['ratings'] = $get_weekly_rating['TeacherWeeklyRating']['averageRate'];
1728            }
1729        }
1730
1731        /* -- NC-5293 start -- */
1732        $this->loadModel('Translation');
1733        $translationCategories = Configure::read('translation_categories');
1734        $translateParams = array(
1735            'languageCode' => $this->lang_iso,
1736            'categoryId' => $translationCategories['teacher_message'],
1737            'messageId' => $teacher->id,
1738            'text' => $teacher->message
1739        );
1740
1741        $translatedMessageParams = $translateParams;
1742        $translateParams['categoryId'] = $translationCategories['teacher_self_introduction_third_pp'];
1743        $translateParams['text'] = $teacher->self_introduction_third_pp;
1744        $translatedSelfIntroductionThirdPpParams = $translateParams;
1745        /* -- NC-5293 end -- */
1746
1747        // Translate and save translated data
1748        $globalTranslate = TeacherTable::translate(array(
1749            'id' => $teacherId,
1750            'lang'=> isset($this->localizeDir) ? $this->localizeDir : Configure::read('default.user_language'),
1751            'controller' => static::class
1752        ));
1753        $translatedMessageTranslation = isset($globalTranslate['message']) ? $globalTranslate['message'] : null;
1754        $translatedThirdppTranslation = isset($globalTranslate['self_introduction_third_pp']) ? $globalTranslate['self_introduction_third_pp'] : null;
1755        $this->set('message', $translatedMessageTranslation);
1756        $this->set('intro', $translatedThirdppTranslation);
1757
1758        //find the selfintro 
1759        $TeacherTable = new TeacherTable($teacher);
1760        $_userSelfIntro = $TeacherTable->iSNotDisplayHtmlTags($teacher->message);
1761        $_userSelfIntro = strip_tags($_userSelfIntro); 
1762
1763        //set the new meta description
1764        $metaDescWD = TeacherTable::getMetaDescription2($_userSelfIntro);
1765        $this->set('meta_description', $metaDescWD);
1766
1767        $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($data['User']['payment_plan_id']);
1768        $canCoinPurchase = true;
1769        if (isset($data['User']['corporate_id']) && isset($corporateType)) {
1770            if (in_array($corporateType, array(Configure::read('corporate_type.standard'), Configure::read('corporate_type.premium')))) {
1771                $canCoinPurchase = true;
1772            } else {
1773                $canCoinPurchase = false;
1774            }
1775        }
1776
1777        //
1778        $teacherCurrentRankId = ClassRegistry::init('Teacher')->getTeacherCurrentRankId($teacher->id);
1779
1780        # Get teachers reservation amounts. | NJ-2038, for hb teachers only not applicable for counselor/avatar
1781        $coinParams =  array(
1782            'current_rank_id' => $teacherCurrentRankId,
1783            'reserve_coin_data_id' => $teacher->reserve_coin_data_id,
1784            'reserve_coin_settings_flg' => $tutorCategory->reserve_coin_settings_flg,
1785            'student_native_option' => $userData->native_option,
1786            'home_flg' => $teacher->home_flg,
1787            'counseling_flg' => $teacher->counseling_flg,
1788            'avatar_parent_flg' => $teacher->avatar_parent_flg,
1789            'avatar_flg' => $teacher->avatar_flg,
1790            'native_speaker_flg' => $teacher->native_speaker_flg
1791        );
1792
1793        // get teacher coin settings
1794        $teacherCoinData = $this->Teacher->getTeacherReserveCoin($coinParams);
1795
1796        $teacherCoinWithOp = $teacherCoinBeforeDiscount = null;
1797        $displayNativeOptionAmountFlg = false;
1798        if($teacherCoinData){
1799            // set teacher reservation coin
1800            $teacherCoin = (isset($teacherCoinData['reserve_coin']) && is_numeric($teacherCoinData['reserve_coin'])) ? $teacherCoinData['reserve_coin'] : 0;
1801            $teacherCoinBeforeDiscount = $teacherCoinData['reserve_coin_before_discount'];
1802            $teacherCoinWithOp = $teacherCoinData['reserve_coin_with_op'];
1803            $displayNativeOptionAmountFlg = $teacherCoinData['display_native_option_amount_flg'];
1804        }
1805        $teacherCoin = $teacherCoin ?? 0;
1806        $callanCoin = ($teacher->callan_halfprice_flg) ? $teacherCoin / 2 : $teacherCoin;
1807
1808        $teacherCallanDiscount = $teacher->getCallanHalfPrice();
1809
1810        $sapuriCoin = 0;
1811        if ($this->isStudySapuriUser) {
1812            $teacherParams = array(
1813                'teacher_id' => $teacher->id,
1814                'current_rank_id' => $teacherCurrentRankId
1815            );
1816            $sapuriCoin = $this->Teacher->getStudySapuriCoin($teacherParams);
1817        }
1818
1819        $ongoingLessonWithOtherStudentButtonDelay = 0;
1820        if($onairDataArr){
1821            if( 
1822                (isset($onairDataArr['user_id']) && $onairDataArr['user_id'] != $userId) && 
1823                (isset($onairDataArr['status']) && $onairDataArr['status'] == '3') && 
1824                (int)$this->studentLessonPriorityTimeDelayInSeconds > 0
1825            ) {
1826                $ongoingLessonWithOtherStudentButtonDelay = 1;
1827            }    
1828        }
1829    
1830        // set lesson review modal on/off
1831        $this->set('lesson_review_flg', $data['User']['lesson_review_flg']);
1832        $where = array(
1833            'UsersFavorite.teacher_id' => $teacherId,
1834        );
1835
1836        $favoriteCount = $this->UsersFavorite->find('count', array('conditions' => $where));
1837        $teacherFavColor = $this->UsersFavoriteCategoriesTeacher->getColorFavTeacherByIds(['user_id' => $this->Auth->user('id'), 'teacher_ids' => $isFav? [$teacher->id]: []]);
1838        $teacherFavsColors = $this->UsersFavoriteCategoriesTeacher->parseToHexColor([
1839            'favIds' => $isFav? [$teacher->id]: [],
1840            'favIdsTeacherCategory' => $teacherFavColor
1841        ]);
1842        
1843        // NJ-3696
1844        $this->LessonOnairsLog->openDBReplica();
1845        $textbook = $this->LessonOnairsLog->find('first', array(
1846            'fields' => array(
1847                'TextbookCategories.id',
1848                'TextbookCategories.textbook_category_type'
1849            ),
1850            'joins' => [
1851            [
1852                'table' => 'textbook_connects',
1853                'alias' => 'TextbookConnects',
1854                'type' => 'left',
1855                'conditions' => ["TextbookConnects.id = LessonOnairsLog.connect_id"]
1856            ],
1857            [
1858                'table' => 'textbook_categories',
1859                'alias' => 'TextbookCategories',
1860                'type' => 'left',
1861                'conditions' => ['TextbookCategories.id = TextbookConnects.category_id']
1862            ]
1863        ],
1864            'conditions' => array('LessonOnairsLog.chat_hash' => $chatHash),
1865            'recursive' => -1
1866        ));
1867        $this->LessonOnairsLog->closeDBReplica();
1868    
1869        if(!$textbook){
1870            $this->LessonOnair->openDBReplica();
1871            $textbook = $this->LessonOnair->find('first', array(
1872                'fields' => array(
1873                    'TextbookCategories.id',
1874                    'TextbookCategories.textbook_category_type'
1875                ),
1876                'joins' => [
1877                    [
1878                        'table' => 'textbook_connects',
1879                        'alias' => 'TextbookConnects',
1880                        'type' => 'left',
1881                        'conditions' => ["TextbookConnects.id = LessonOnair.connect_id"]
1882                    ],
1883                    [
1884                        'table' => 'textbook_categories',
1885                        'alias' => 'TextbookCategories',
1886                        'type' => 'left',
1887                        'conditions' => ['TextbookCategories.id = TextbookConnects.category_id']
1888                    ]
1889                ],
1890                'conditions' => array('LessonOnair.chat_hash' => $chatHash),
1891                'recursive' => -1
1892            ));
1893            $this->LessonOnair->closeDBReplica();
1894        }
1895
1896        //NJ-20590
1897        $teacher->image_url = myTools::checkAndReturnPresignedUrl($teacher->image_url);
1898
1899
1900        $hash = $this->request->query['chatHash'] ?? null;
1901        if(!empty($hash)){
1902            if (!class_exists('myMemcached')) {
1903                App::uses('myMemcached', 'Lib');
1904            }
1905            $memcached = new myMemcached();
1906            $appreciationDoneCache = $memcached->get("appreciation_done_".$hash);
1907            $this->set("isAppreciationDone", $appreciationDoneCache == 1 ? 1 : 0);
1908        }
1909
1910        // NJ-NJ-62396
1911        $isCallanTextbook = (!empty($textbook['TextbookCategories']['textbook_category_type']) && in_array($textbook['TextbookCategories']['textbook_category_type'], Configure::read('callan_textbook_type'))) ? 1 : 0;
1912
1913
1914        // NJ-3696
1915        // set view vars
1916        $setData = array(
1917            'textbookCategory' => $textbook['TextbookCategories'] ?? [],
1918            'teacher' => $teacher,
1919            'onair' => $oOnair,
1920            'isFav' => $isFav,
1921            'isHide' => $isHide,
1922            'ongoingLessonWithOtherStudentButtonDelay' => $ongoingLessonWithOtherStudentButtonDelay,
1923            'initialTeacherStatus' => $initialTeacherStatus,
1924            'teacherFavsColors' => $teacherFavsColors,
1925            'favoriteCount' => $favoriteCount,
1926            'tId' => $teacher->id,
1927            'user' => $user,
1928            'lessonAvailable' => isset($lessonAvailable['lessonAvailable']) ? $lessonAvailable['lessonAvailable'] : 0,
1929            'userMembership' => isset($userMembership)?$userMembership:'',
1930            'adminFlag' => isset($user['admin_flg'])?$user['admin_flg']:'0',
1931            'enquate6_options' => UserTable::getEnquate6(),
1932            'enquate7_options' => UserTable::getEnquate7(),
1933            'stusapLessonCount' => $stusapLessonCount,
1934            'lessonCount' => $lessonCount,
1935            'commentCount' => $commentCount,
1936            'userId' => $userId,
1937            'cardAuth' => PaymentTable::checkIfCardAuth($this->Auth->user('id'), $this->Auth->user('hash16')),
1938            'teacherCoin' => empty($teacherCoin)? 0: (int)$teacherCoin,
1939            'callanCoin' => (int)$callanCoin,
1940            'teacherCallanDiscount' => empty($teacherCallanDiscount)? 0: $teacherCallanDiscount,
1941            'isCallanTextbook' => $isCallanTextbook,
1942            'UserData' => $data,
1943            'userCountry' => $userCountry,
1944            'velifyCount' => $velifyCount,
1945            'firstTimeLoggedIn' => $firstTimeLoggedIn,
1946            'isLoggedIn' => $this->Auth->loggedIn(),
1947            'country' => $country,
1948            'timeDiff' => $timeDiff,
1949            'corporateId' => !empty($data['User']['corporate_id']) ? $data['User']['corporate_id'] : $this->Auth->user('corporate_id'),
1950            'translatedMessageParams' => $translatedMessageParams,
1951            'translatedSelfIntroductionThirdPpParams' => $translatedSelfIntroductionThirdPpParams,
1952            'translationModel' => $this->Translation,
1953            'weekly_ratings' => isset($get_weekly_rating['TeacherWeeklyRating']) ? $get_weekly_rating['TeacherWeeklyRating'] : 0,
1954            'hideLimitedPlanReservation' => $hideLimitedPlanReservation,
1955            'canCoinPurchase' => $canCoinPurchase,
1956            'liveStatus' => $liveStatus,
1957            'teacherCoinWithOp' => empty($teacherCoinWithOp)? 0: (int)$teacherCoinWithOp,
1958            'nativeOptionFlg' => $displayNativeOptionAmountFlg,
1959            'teacherCoinBeforeDiscount' => empty($teacherCoinBeforeDiscount)? 0: (int)$teacherCoinBeforeDiscount,
1960            'sapuriCoin' => $sapuriCoin,
1961            'isEmergencyPage' => !empty($this->request->query['emergency']) ? true : false,
1962            'teacherTitleThreshold' => $teacherTitleThreshold,
1963        );
1964
1965        $this->set($setData);
1966        if ($userId) {
1967            $points = $this->UsersPoint->find('first', array(
1968                'fields' => array('point'),
1969                    'conditions' => array(
1970                        'user_id' => $userId
1971                    )
1972                )
1973            );
1974
1975            $points = isset($points['UsersPoint']['point']) ? $points['UsersPoint']['point'] : 0;
1976            $reservePoint = Configure::read("reserve_point");
1977
1978            if (intval($reservePoint) < 1) $reservePoint = 0;
1979            //set promo discount for reservation
1980            // set paramater to 2 for reservation promo
1981            $bonus = CoinSetTable::getCoinSet(2);
1982            //check if the promo is valid today
1983            if ($bonus) {
1984                $reservePoint = $bonus;
1985            }
1986        } else {
1987            $points = 0;
1988        }
1989
1990        # get user timezone
1991        $user_timezone_id = (isset($this->sharedUserData['User']['timezone_id'])) ? $this->sharedUserData['User']['timezone_id'] : 203;
1992        $user_timezone_data = $this->Timezone->find('first',
1993            array(
1994                'fields' => array(
1995                    'Timezone.city_eng',
1996                    'Timezone.utc_offset',
1997                    'Timezone.country_code_id'
1998                ),
1999                'conditions' => array(
2000                    'Timezone.id' => $user_timezone_id
2001                ),
2002                'recursive' => -1
2003            )
2004        );
2005
2006        // - NJ-3653 get country
2007        $countryTimezone = null;
2008        if (!empty($user_timezone_data) && $user_timezone_data['Timezone']['country_code_id']) {
2009            // - Get all country Code
2010            $countryOptions = $this->Timezone->countryOptions();
2011
2012            $countryCodeId = $user_timezone_data['Timezone']['country_code_id'];
2013            $countryName = $countryOptions[$countryCodeId]['country_name'];
2014
2015            if (isset($countryName) && $countryName) {
2016                $countryTimezone = $countryName;
2017            }
2018        }
2019
2020        $this->set('countryTimezone', $countryTimezone);
2021        $this->set('userTimezoneData', $user_timezone_data);
2022
2023        #user time
2024        $datetime = date('Y-m-d H:i:s');
2025        $localTime = $this->displayTime;
2026        // NJ-29496
2027        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) { 
2028            $formattedDate = date('d/m/Y G:i', $localTime);
2029        } else {
2030            $formattedDate = date('Y/m/d G:i', $localTime);
2031        }
2032        $this->set('userCurrentTime', $formattedDate);
2033
2034        $this->set('points', $points);
2035        $this->set('reservePoint', isset($reservePoint)? $reservePoint: 0);
2036
2037        $countrids_no = Configure::read('sms_send.countrids_no');
2038        $this->set('countrids_no', $countrids_no);
2039
2040        $deviceNotSupported = false;
2041        $ua = (!empty(myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']))) ? myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']) : '';
2042        if (strpos($ua, 'Android') !== false || strpos($ua, 'iPhone') !== false || strpos($ua, 'iPad') !== false || strpos($ua, 'iPod') !== false) {
2043            $deviceNotSupported = true;
2044        }
2045        $this->set('deviceNotSupported', $deviceNotSupported);
2046
2047        $userLang = !empty($this->localizeDir) ? $this->localizeDir : Configure::read('english_language_id');
2048        $languageIds = $this->CountryCode->getLanguageList(['field'=>'iso_639_1']);
2049        $getCRData = $this->Teacher->getCountryResidenceData($teacherId, $userLang, 'first', $languageIds);
2050        $residenceData = $this->getResidenceData($getCRData);
2051        $this->set('residenceData',$residenceData);
2052        $this->set('residenceFlg',$residenceData['countryFlag']);
2053        $this->set('deviceNotSupported', $deviceNotSupported);
2054        $this->set('statusCheck', array(1, 4));
2055
2056        $this->set('login', $this->Auth->loggedIn());
2057        $preset = array();
2058        if($this->Auth->User('id')) {
2059            //get preset textbook -> last viewed -> default textbook category first lesson
2060            $presetParams = array("user_id" => $this->Auth->User('id'));
2061
2062            //NC-8728 check if user is valid for Study Sapuri Business English Daily textbooks
2063            $presetParams["userValidForSSBEDT"] = $this->userValidForSSBEDT();
2064            //add additional parameters
2065            if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))) {
2066                $presetParams["lang"] = $this->localizeDir;
2067            }
2068
2069            #NC-9916
2070            if($data['User']) {
2071                $presetParams['native_language2'] = $userData->native_language2;
2072                $presetParams["userMembershipType"] = $userData->getMembershipTypeIndex();
2073            }
2074
2075            $preset_data = $this->UsersTextbookInfo->getPreset($presetParams);
2076            if(isset($preset_data['preset_connect_id']) && !empty($preset_data['preset_connect_id'])) {
2077                # for preset
2078                $presetParams['connect_id'] = $preset_data['preset_connect_id'];
2079                $presetParams['last_opened_date'] = $preset_data['preset_last_viewed_date'];
2080
2081            } else if(isset($preset_data['last_viewed_connect_id']) && !empty($preset_data['last_viewed_connect_id'])) {
2082                # use last viewed textbook if no preset data.
2083                $presetParams['connect_id'] = $preset_data['last_viewed_connect_id'];
2084                $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
2085
2086            }
2087
2088            // - NJ-3878 : add trapping for pc and app(api) 1 = pc 0 = app
2089            $presetParams['is_pc_flg'] = 1;
2090
2091            # fetch preset
2092            $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
2093            if(!$preset) {
2094                unset($presetParams['connect_id']);
2095                unset($presetParams['last_opened_date']);
2096                $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
2097            }
2098        }
2099
2100        //set variable preset textbook to be displayed
2101        $this->set('preset', $preset);
2102
2103        // NJ-8416: check for textbook live_lesson_flg is ON
2104        $textbookCategory = isset($preset['textbook_info']['TextbookCategory']) ? $preset['textbook_info']['TextbookCategory'] : array();
2105        $presetIsLiveTextbook = (isset($textbookCategory['live_lesson_flg']) && $textbookCategory['live_lesson_flg']) ? true : false;
2106        $this->set('presetIsLiveTextbook', $presetIsLiveTextbook);
2107
2108        // apology list (cancellation of reservation)
2109         $apologyList = array(); // NC-4749 : hide list, used function from model and made it popup modal
2110
2111         // -- NJ-18780: is normal lite plan user 
2112        $_paymentPlanID = isset($this->sharedUserData['User']['payment_plan_id']) ? $this->sharedUserData['User']['payment_plan_id'] : null;
2113        $isNormalLitePlanUser = (in_array($_paymentPlanID, Configure::read('lite_payment_plans') ) ) ? true : false;
2114
2115        $this->set('apologyList', $apologyList);
2116        $disabledSchedule = $this->LessonSchedule->getDisabledDaysPC(array(
2117            'userId' => $this->Auth->user('id'),
2118            'teacherId' => $teacherId,
2119            'timeDiff' => $this->timeDiff,
2120            'isNormalLitePlanUser' => $isNormalLitePlanUser
2121        ));
2122        $this->set('disabledSchedule', json_encode($disabledSchedule));
2123        $this->set('showNoticeMaxLimit', (isset($disabledSchedule['disableAll']) ? $disabledSchedule['disableAll'] : false));
2124        $this->set('noIndexFlgOveride', ($this->localizeDir != Configure::read('default.user_language') ? true : false));
2125        $this->set('isNormalLitePlanUser',$isNormalLitePlanUser);
2126
2127        //NC-7603 get keep memo
2128        $getKeepMemo = $this->UsersMemo->find('first', array(
2129            'fields' => array(
2130                'id',
2131                'memo'
2132            ),
2133            'conditions' => array(
2134                'user_id' => $this->Auth->user('id'),
2135                'teacher_id' => $teacherId,
2136                'type' => 0
2137            ),
2138            'order' => array('created DESC'),
2139        ));
2140
2141        $this->set('keep_memo', $getKeepMemo);
2142
2143        // NC-8020
2144        $this->set('textbookConnectId', $preset['textbook_connect_id']);
2145        $this->set('textbookCategoryTypeId', $preset['textbook_type']);
2146
2147        // - NJ-6390 add highLightFlag
2148        $this->set('highLightFlag', isset($highLightFlag) && $highLightFlag? $highLightFlag: null);
2149
2150        // NJ-42
2151        $liveCoin = $this->LessonOnairsViewer->getLiveLessonCoinPrice(['current_rank_id' => $teacher->current_rank_id]);
2152        $this->set('liveCoin', number_format((float)$liveCoin));
2153
2154        $this->set('order', $this->Cookie->read('teacherReviewOrder') ?? 0);
2155        //NC-7984 start
2156        $lesson_history_data = $this->LessonSchedule->latestLessonHistory($teacherId, $this->Auth->user('id'), $this->localizeDir);
2157        if(!empty($lesson_history_data)) {
2158            $this->set('lessonHistory', $lesson_history_data['lessonHistory']);
2159            $this->set('textbookNamesCachedArr', $lesson_history_data['textbookNamesCachedArr']);
2160        }
2161        //NC-7984 end
2162        
2163        $showRating = $teacher->getReviewOption($teacher->rank_coin_id);
2164        $this->set('showRating', $showRating);
2165
2166        //NJ-20069 teacher
2167        $reserveAndCancel = $this->getReserveAndCancelled($teacherId);
2168        $lessonHistory = $this->LessonSchedule->latestLessonHistory($teacherId, $this->Auth->user('id'), $this->localizeDir, null);
2169        $lessonHistoryCount  = count($lessonHistory['lessonHistory']);
2170        $latestUserLesson = isset($lessonHistory['lessonHistory'][0]['LessonOnairsLog']) ? $lessonHistory['lessonHistory'][0]['LessonOnairsLog'] : null;
2171        $teacherFavoriteCount = $this->UsersFavorite->getFavoriteCount($teacherId);
2172        
2173        // - if has translated Category name
2174        if (isset($lessonHistory['lessonHistory'][0]['GlobalTextbookCategory']['gl_name']) && $lessonHistory['lessonHistory'][0]['GlobalTextbookCategory']['gl_name']) {
2175            $lessonHistory['lessonHistory'][0]['TextbookCategory']['name'] = $lessonHistory['lessonHistory'][0]['GlobalTextbookCategory']['gl_name'];
2176        }
2177        
2178        $formattedLatestLessonData = "";
2179        if(!empty($latestUserLesson))
2180        $formattedLatestLessonData = date('Y-m-d',strtotime($latestUserLesson['start_time'])). " (" . date('D',strtotime($latestUserLesson['start_time'])) . ") ";
2181        
2182        $teacherLastLogin = $teacher->last_login_time;
2183        $formattedTeacherLastLogin = "";
2184        if(!empty($teacherLastLogin)) {
2185            if ($this->localizeDir == 'pt-br') {
2186                $daysOfWeekPtBr = [
2187                    'Sun' => __dx('account', 'week', '日'), // Dom
2188                    'Mon' => __dx('account', 'week', '月'), // Seg
2189                    'Tue' => __dx('account', 'week', '火'), // Ter
2190                    'Wed' => __dx('account', 'week', '水'), // Qua
2191                    'Thu' => __dx('account', 'week', '木'), // Qui
2192                    'Fri' => __dx('register', 'week', '金'), // Sex
2193                    'Sat' => __dx('account', 'week', '土')  // Sab
2194                ];
2195                $dayOfWeekPtBr = $daysOfWeekPtBr[date('D', strtotime($teacherLastLogin))];
2196        $formattedTeacherLastLogin = date('d/m/Y', strtotime($teacherLastLogin)) . " ({$dayOfWeekPtBr}";
2197            } else {
2198                $formattedTeacherLastLogin = date('Y-m-d',strtotime($teacherLastLogin)). " (" . date('D',strtotime($teacherLastLogin)) . ") ";
2199            }
2200        }
2201
2202        $this->set('lessonHistoryCount', $lessonHistoryCount);
2203        $this->set('latestUserLesson', isset($lessonHistory['lessonHistory'][0]) ? $lessonHistory['lessonHistory'][0] : null);
2204        $this->set('teacherRates', $reserveAndCancel);
2205        $this->set('teacherIdCheck', $teacherId);
2206        $this->set('latestLessonData', $formattedLatestLessonData);
2207        $this->set('teacherLastLogin', $formattedTeacherLastLogin);
2208        $this->set('teacherFavoriteCount', $teacherFavoriteCount);
2209
2210        $this->TeacherFeature->openDBReplica();
2211        $teacherFeatures = $this->TeacherFeature->find('first', array(
2212            'conditions' =>  array(
2213                'TeacherFeature.teacher_id' => $teacherId
2214            )
2215        ));
2216        $this->TeacherFeature->closeDBReplica();
2217        
2218        # NJ-19429: fetch campaign
2219        $studentID = $this->Auth->user('id');
2220        $inCampaignDetails = $this->CampaignInstructor->getValidateUserCampaign($teacherId, $studentID);
2221
2222        //NJ-47494 - add 8 day checker for campaign
2223        $now = date('Y-m-d');
2224        $dayTimer = date('Y-m-d', strtotime('+7 days'));
2225        
2226        $inCampaignStartDate = isset($inCampaignDetails['CampaignInstructor']['start_date']) ? date('Y-m-d', strtotime($inCampaignDetails['CampaignInstructor']['start_date'])) : null;
2227        $inCampaignEndDate = isset($inCampaignDetails['CampaignInstructor']['end_date']) ? date('Y-m-d', strtotime($inCampaignDetails['CampaignInstructor']['end_date'])) : null;
2228        $validCampaignDate = !($dayTimer < $inCampaignStartDate || $now > $inCampaignEndDate);
2229
2230        if ($inCampaignDetails && $validCampaignDate == 1){
2231            $campaign = $inCampaignDetails['CampaignInstructor'];
2232
2233            $campaignTag = '';
2234            if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) { // if the language is Custom language format
2235                $campaignTag .= $campaign['discount'] == 100 ? '100% OFF ' : '50% OFF ';
2236                $campaignTag .= '(' . __d('waiting',Configure::read('campaign_instructor_textbook_type')[$campaign['textbook_type']]) . ') ';    
2237
2238                // NJ-47838 GGPE FB10
2239                if((int) $campaign['classification'] == 4) {
2240                    $campaignTag = __d('waiting', Configure::read('campaign_instructor_tags')[$campaign['campaign_tag_id']]);
2241                }
2242            } else { // if the language is not Custom language format
2243                $campaignTag .= $campaign['discount'] == 100 ? '100%OFF ' : '50%OFF ';
2244                $campaignTag .= '('.Configure::read('campaign_instructor_textbook_type')[$campaign['textbook_type']]. ') ';
2245                $campaignTag .= Configure::read('campaign_instructor_type')[$campaign['classification']] . '講師';
2246            }
2247
2248            $teacherFeatures['CampaignTag'] = $campaignTag;
2249
2250            // NJ-47838
2251            $teacherFeatures['CampaignTagClassification'] = $campaign['classification'];
2252            // NJ-47838 : Set a flag if the campaign is classified as "Live"
2253            $teacherFeatures['IsCampaignLive'] = ($campaign['classification'] === 4);
2254
2255            // NJ-47838 : Ensure the campaign discount is set if the campaign is live and the teacher is registered for it
2256            if ($teacherFeatures['IsCampaignLive']) {
2257                $teacherFeatures['CampaignLiveDiscount'] = $campaign['discount'];
2258            }
2259        }
2260
2261        if(isset($campaign) && $campaign){
2262            $this->set('campaignDiscount', isset($campaign['discount']) ? $campaign['discount'] : null);
2263            $this->set('campaignTextbook', isset($campaign['textbook_type']) ? $campaign['textbook_type'] : null);
2264            $this->set('campaignDiscountClassification', isset($campaign['classification']) ? $campaign['classification'] : null);
2265        }
2266
2267        $this->set('teacherFeatures', $teacherFeatures);
2268        
2269        // NJ-3786 textbook teacher recommendation
2270        $curDate = date('Y-m-d');
2271        $userId = $this->Auth->user('id') ? $this->Auth->user('id') : null;
2272        $txtTeacherRecommendlimit = 10;
2273        $userData = isset($this->sharedUserData['User']) && $this->sharedUserData['User'] ? $this->sharedUserData['User'] : null;
2274        $endDate = date('Y-m-d',strtotime('-1 day' ,strtotime($curDate)));
2275        $beginDate = date('Y-m-d',strtotime('-1 month' ,strtotime($curDate)));
2276
2277        if( $userId ) {
2278            // - NJ-8416: check for last lesson type
2279            $lastLessonType = ClassRegistry::init('LessonOnair')->getLastLessonType($userId);
2280            $this->log('[NJ-8416 lastLessonType waitingDetail] -> ' . json_encode($lastLessonType), 'debug');
2281            $lastBookUsedData = $this->UsersTextbookInfo->getCurrentTextbookAndBadgeData( array( 
2282                'user_id' => $userId,
2283                'limit' => 10, // waiting detail page
2284                'last_lesson_type' => $lastLessonType
2285            ) );
2286            $textbookCategoryId = $lastBookUsedData['category_id'];
2287            $textbookBadge = $lastBookUsedData['textbook_badge'];
2288            $this->log('[NJ-8416 textbookCategoryId waitingDetail] -> ' . json_encode($textbookCategoryId), 'debug');
2289            $paramsArr = array(
2290                'user_id' => $userId,
2291                'begin_date' => $beginDate,
2292                'end_date' => $endDate,
2293                'textbook_category' => $textbookCategoryId,
2294                'textbook_badge' => $textbookBadge,
2295                'limit' => $txtTeacherRecommendlimit,
2296                'user_data' => $userData,
2297                'exclude_teacher_id' => $teacherId
2298            );
2299
2300            $teacherTextbookStatData = $this->TeacherTextbookStat->fetchTextbookTeacherRatingData($paramsArr);
2301            if( $teacherTextbookStatData ) {
2302                $dataList = $this->arrangeTeacherRecommendList( array( 
2303                        'user_id' => $userId,
2304                        'data' => $teacherTextbookStatData,
2305                        'category_id' => $textbookCategoryId,
2306                        'user_data' => $userData
2307                    ) 
2308                );
2309                $this->set('textbookTeacherData', $dataList);
2310            }
2311        }
2312
2313        $ownReservationTeacherData = $this->LessonSchedule->getWaitingToJoinReservationTeacherInfo( array( 'user_id' => $this->Auth->user('id'), 'limit_checker_flag' => 1 ) );
2314        $this->set( 'ownReservationTeacherId', $ownReservationTeacherData['teacher_id'] ); // live lesson work-around
2315        $this->set( 'lessonScheduleOwnReservationTeacher', isset($lessonScheduleOwnReservationTeacherData['teacher_id']) ? $lessonScheduleOwnReservationTeacherData['teacher_id'] : null ); // live lesson work-around
2316        $this->set( 'studentDelayInSeconds', (int)$studentDelayInSeconds );
2317        $this->set( 'remainingSeconds', (int)$remainingSeconds );
2318        $this->set( 'ownReservationFlg', $ownReservationFlg );
2319        $this->set( 'teacherStatusColor', $teacherStatusColor );
2320
2321        if ($this->request->query('chatHash')) {
2322            $chatHash = $this->request->query('chatHash');
2323
2324            $allData = $this->LessonOnairsLog->find('first', $this->checkHash('LessonOnairsLog',$chatHash));
2325            $this->set('data',  $allData);
2326
2327            $friParams = array(
2328                'type' => 0,
2329                'langId' => $this->CountryCode->getUserLanguageId($this->localizeDir),
2330                'from' => 'user'
2331            );
2332
2333            $strengthItems = $this->FeatureRatingItem->getActiveItems($friParams);
2334
2335            // get active weakness feature rating items
2336            $friParams['type'] = 1;
2337            $weaknessItems = $this->FeatureRatingItem->getActiveItems($friParams);
2338
2339            $this->set('strengthItems', $strengthItems);
2340            $this->set('weaknessItems', $weaknessItems);
2341            
2342            $allData = $this->LessonOnairsLog->find('first', $this->checkHash('LessonOnairsLog',$chatHash));
2343
2344            if(!$allData) { // if LessonOnairsLog's chat_hash returns null/empty , retrieve record from lessonOnair
2345                $allData = $this->LessonOnair->find('first', $this->checkHash('LessonOnair',$chatHash));
2346
2347                if(!$allData) {
2348                    return $this->redirect(array('controller' => 'home', 'action' => 'index', 'home'));
2349                }
2350            }
2351
2352            $this->set('data',  $allData);
2353
2354            $live_lesson_viewer = 0;
2355            if((!empty($allData['LessonOnairsLog']) && $allData['LessonOnairsLog']['live_lesson_flg'] == 1 && $allData['LessonOnairsLog']['user_id'] != $userId)
2356                || (!empty($allData['LessonOnair']) && $allData['LessonOnair']['live_lesson_flg'] == 1 && $allData['LessonOnair']['user_id'] != $userId)
2357            ) { $live_lesson_viewer = 1; }
2358            
2359            // get last feature rating items
2360            if($live_lesson_viewer){
2361                $lastRatingItems = $this->ViewerFeatureRatingLastVoted->getLastEvalItems(array('teacherId' => $teacherId, 'userId' => $userId));
2362            } else {
2363                $lastRatingItems = $this->UserFeatureRatingLastVoted->getLastEvalItems(array('teacherId' => $teacherId, 'userId' => $userId));
2364            }
2365            
2366            $this->set('lastSelectedStrengthItems', isset($lastRatingItems['strengthItems']) ? $lastRatingItems['strengthItems'] : array());
2367            $this->set('lastSelectedWeaknessItems', isset($lastRatingItems['weaknessItems']) ? $lastRatingItems['weaknessItems'] : array());
2368
2369            $userValidForSSBEDT = false;
2370            if (isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')){
2371                $userValidForSSBEDT = true;
2372            }
2373            $param = array(
2374                "user_id" => $userId,
2375                "select_method" => "first",
2376                "env_flag" => "all",
2377                'connect_id' => $allData['Connect']['id'],
2378                "user_locale" => $this->localizeDir,
2379                "userValidForSSBEDT" => $userValidForSSBEDT
2380            );
2381            //NJ-12326
2382            if ($userId && isset($allData['Connect']['category_id']) && $allData['Connect']['category_id']) {
2383                $corporateParams = array('user_id' => $userId);
2384                $corporateTextbookControlFlg = $this->Corporate->getCorporateTextbookControl($corporateParams);
2385                
2386                if ($corporateTextbookControlFlg == 1) {
2387                    $categoryData = $this->TextbookCategory->getKidsCategoryTypesById($allData['Connect']['category_id']);
2388                    if (!empty($categoryData)) {
2389                        $param['include_kids_category'] = $allData['Connect']['category_id'];
2390                    }
2391                }
2392            }
2393            $textbookData = $this->Textbook->getTextbooks($param);
2394            $data = $textbookData['res_data'];
2395
2396            $isReservedLesson = 2;
2397            $hideTextbookChangeModal = $enableNextTextbookChapterButton = 'false';
2398            $latestPresetTextbookConnect_id = (int)$data['TextbookConnect']['id'];
2399            $latestPresetTextbookConnect_categoryId = (int)$data['TextbookConnect']['category_id'];
2400            $latestPresetTextbookConnect_subCategoryId = (int)$data['TextbookConnect']['subcategory_id'];
2401            $latestPresetTextbookCategory_textbookCatType = (int)$data['TextbookCategory']['textbook_category_type'];
2402
2403            //NJ-3626 Optimize PC /lesson-finish page
2404            $lessonOnairLatestData = $this->LessonOnair->getLatestLessonOnairDetailsOfUserAndTeacher($userId, $teacherId);
2405            if(isset($lessonOnairLatestData) && $lessonOnairLatestData) {
2406                $lessonOnairLatestDataFlg = true;
2407                $lessonOnairLatest_connectId = (int)$lessonOnairLatestData['LessonOnair']['connect_id'];
2408                $lessonOnairLatest_lessonType = (int)$lessonOnairLatestData['LessonOnair']['lesson_type'];
2409            } else {
2410                $lessonOnairLogsLatestData = $this->LessonOnairsLog->getLatestLessonLogsDetailsOfUserAndTeacher($userId, $teacherId);
2411                if(isset($lessonOnairLogsLatestData) && $lessonOnairLogsLatestData) {
2412                    $lessonOnairLogsLatest_connectId = (int)$lessonOnairLogsLatestData['LessonOnairsLog']['connect_id'];
2413                    $lessonOnairLogsLatest_lessonType = (int)$lessonOnairLogsLatestData['LessonOnairsLog']['lesson_type'];
2414                }
2415            }
2416
2417            // - initialize empty variable
2418            $isLatestPresetTextbookMadeDuringLastLesson = [];
2419            $latestPresetTextbookParams = [];
2420
2421            // For hiding of textbookchange modal (if reserved lesson & not studySapuri)
2422            if ($lessonOnairLatestDataFlg) {
2423                $latestPresetTextbookParams = array (
2424                    'userId' => $userId,
2425                    'latestPresetTextbookConnect_id' => $latestPresetTextbookConnect_id,
2426                    'lessonOnairLatest_startTime' => $lessonOnairLatestData['LessonOnair']['start_time'],
2427                    'lessonOnairLatest_endTime' => $lessonOnairLatestData['LessonOnair']['end_time']
2428                );
2429
2430            // - if has lesson onairs log
2431            } else if ($lessonOnairLogsLatestData) {
2432                $latestPresetTextbookParams = array (
2433                    'userId' => $userId,
2434                    'latestPresetTextbookConnect_id' => $latestPresetTextbookConnect_id,
2435                    'lessonOnairLogsLatest_startTime' => $lessonOnairLogsLatestData['LessonOnairsLog']['start_time'],
2436                    'lessonOnairLogsLatest_endTime' => $lessonOnairLogsLatestData['LessonOnairsLog']['end_time']
2437                );
2438
2439            }
2440            
2441            // - if has parameters for fetching latest textbook parameters
2442            if ($latestPresetTextbookParams) {
2443                $isLatestPresetTextbookMadeDuringLastLesson = $this->UsersTextbookInfo->checkLatestUserTextbookInfoChangedDuringLesson($latestPresetTextbookParams);
2444            }
2445
2446            // -  check sapuri ID
2447            if(!isset($this->studySapuriId) || !$this->studySapuriId) {
2448                if (isset($lessonOnairLatestDataFlg)) {
2449                    if (is_array($isLatestPresetTextbookMadeDuringLastLesson) && !empty($isLatestPresetTextbookMadeDuringLastLesson)
2450                        && $latestPresetTextbookConnect_id == $lessonOnairLatest_connectId && $lessonOnairLatest_lessonType == $isReservedLesson
2451                    ) {
2452                        $hideTextbookChangeModal = 'true';
2453                    }
2454                } else {
2455                    if (
2456                        is_array($isLatestPresetTextbookMadeDuringLastLesson) && !empty($isLatestPresetTextbookMadeDuringLastLesson)
2457                        && $latestPresetTextbookConnect_id == $lessonOnairLogsLatest_connectId &&  $lessonOnairLogsLatest_lessonType == $isReservedLesson
2458                    ) {
2459                        $hideTextbookChangeModal = 'true';
2460                    }
2461                }
2462            }
2463
2464            $onGoingLesson = $this->LessonOnair->hasOngoingLesson($this->Auth->user('id'));
2465
2466            $this->set('hideTextbookChangeModal', $hideTextbookChangeModal);
2467
2468            // For enabling next textbook chapter button (if not callan and not ongoing lesson)
2469            if (
2470                $hideTextbookChangeModal == 'false'
2471                && (isset($latestPresetTextbookCategory_textbookCatType) &&  !in_array($latestPresetTextbookCategory_textbookCatType, Configure::read('callan_textbook_type')))
2472                && (isset($onGoingLesson) && $onGoingLesson == false)
2473            ) {
2474                $allTextbookParams = array(
2475                    'category_id' => $latestPresetTextbookConnect_categoryId, 
2476                    'connect_id' => $latestPresetTextbookConnect_id,
2477                    'subcategory_id' => $latestPresetTextbookConnect_subCategoryId
2478                );
2479                
2480                $allTextbookChapters = $this->TextbookConnect->getTextbookPrevAndNextFunction($allTextbookParams);
2481                // if has next textbook chapter, show button 
2482                if (
2483                    is_array($allTextbookChapters) && !is_null($allTextbookChapters) 
2484                    && ($allTextbookChapters['next'] !== '' && !is_null($allTextbookChapters['next']))
2485                ) {
2486                    $enableNextTextbookChapterButton = 'true';
2487                }
2488            }
2489
2490            if(!empty($this->sharedUserData['User'])){
2491                // - campaing stamps
2492                $this->getActiveCampaignStampData();
2493            }
2494
2495            $this->set('enableNextTextbookChapterButton', $enableNextTextbookChapterButton);
2496        }
2497
2498        //NJ-18780 : check the user total reservation if lite plan 
2499        $_user = $this->sharedUserData['User'] ?? array();
2500        $liteLimitReservationFlg = 0;
2501
2502        if (
2503            $_user && 
2504            in_array($_user['payment_plan_id'], Configure::read('lite_payment_plans'))
2505        ) {
2506            # fetch the total reservation 
2507            $liteUserReservationCount = $this->LessonSchedule->countUserTotalReservation(array('userId' => $this->Auth->user('id')));
2508
2509            if ($liteUserReservationCount >= Configure::read("lite_plan_maximum_number_of_total_reservation")) {
2510                # show modal
2511                $liteLimitReservationFlg = 1;
2512            }
2513        }
2514
2515        // NJ-18780 : set view 
2516        $this->set('liteLimitReservationFlg',$liteLimitReservationFlg);
2517
2518
2519        $this->set('chatHash', isset($chatHash) ? $chatHash : '');
2520    
2521        //-Live Lesson Phase 3
2522        $this->set('liveLessonFlg', $liveLessonFlg);
2523
2524        //NJ-33414
2525        $this->UsersDetail->openDBReplica();
2526        $fetchUsersDetail = $this->UsersDetail->find('first', array(
2527            'fields' => array(
2528                'lesson_request_flg'
2529            ),
2530            'conditions' =>  array('user_id' => $this->sharedUserData['User']['id']),
2531            'recursive' => -1
2532        ));
2533        $this->UsersDetail->closeDBReplica();
2534
2535        $lessonRequestFlg = $fetchUsersDetail ? $fetchUsersDetail['UsersDetail']['lesson_request_flg'] : 1;
2536        $this->set('lessonRequestFlg',$lessonRequestFlg);
2537
2538        //-- NJ-44869 skip communication modal
2539        $lessonSystemTroubleFlg = 0;
2540        $hideConnectionModalFlg = 0;
2541
2542        if (!empty($chatHash)) {
2543            $memcached = new myMemcached();
2544            $lessonSystemTroubleCache = $memcached->get('lesson_system_trouble_' . $chatHash);
2545    
2546            if (!empty($lessonSystemTroubleCache)) {
2547                $memcached->delete('lesson_system_trouble_' . $chatHash);
2548                $lessonSystemTroubleFlg = 1;
2549            } 
2550        }
2551        
2552        $this->set('lessonSystemTroubleCache', $lessonSystemTroubleFlg);
2553        $this->set('hideConnectionModalFlg', $hideConnectionModalFlg);
2554    }
2555
2556    /**
2557     * @api {post} /user/waiting/getStrengthRating getStrengthRating()
2558     * @apiName getStrengthRating
2559     * @apiGroup Waiting
2560     * @apiDescription Retrieves the strength rating items for a specific teacher in Native Camp. It returns the list of strength rating items.
2561     *
2562     * @apiBody {String} teacherId The ID of the teacher.
2563     * 
2564     * @apiSuccess {Boolean} res Indicates whether the request was successful.
2565     * @apiSuccess {Object[]} strengthItems The list of strength rating items.
2566     *
2567     * @apiSuccessExample {json} Success-Response:
2568     *     {
2569     *         "res": true,
2570     *         "strengthItems": [
2571     *             {
2572     *                 "id": 1,
2573     *                 "name": "Friendly",
2574     *                 "rating": 5
2575     *             }
2576     *         ]
2577     *     }
2578     *
2579     * @apiError {Boolean} res Indicates whether the request was successful.
2580     *
2581     * @apiErrorExample {json} Error-Response:
2582     *     {
2583     *         "res": false
2584     *     }
2585     * 
2586     * @apiSampleRequest off
2587     */
2588    public function getStrengthRating() {
2589        $this->autoRender = false;
2590        $this->layout = false;
2591        $response = json_encode(array('res' => false)); // default
2592
2593        if($this->request->is('post')) {
2594            $post = $this->request->data;
2595            if (!isset($post['teacherId']) && $post['teacherId']) {
2596                return json_encode($response);
2597            }
2598            $teacherId = $post['teacherId'];
2599            
2600            $strengthItemsParams = array(
2601                'teacherId' => $teacherId,
2602                'type' => 0,
2603                'langId' => $this->CountryCode->getUserLanguageId($this->localizeDir)
2604            );
2605
2606            $strengthItems = $this->TeacherFeatureRating->getFeatureRatingItems($strengthItemsParams);
2607            
2608            if(!empty($strengthItems) && $strengthItems) {
2609                $response = json_encode(array(
2610                    'res' => true, 
2611                    'strengthItems' => $strengthItems, 
2612                ));
2613            }
2614        }
2615        return $response;
2616
2617    }
2618
2619    /**
2620     * @api {post} /user/waiting/getLessonHistory getLessonHistory()
2621     * @apiName getLessonHistory
2622     * @apiGroup Waiting
2623     * @apiDescription Retrieves the lesson history for a specific teacher and user in Native Camp. It returns the details of the lessons, including textbook information and chat logs.
2624     *
2625     * @apiBody {String} teacherId The ID of the teacher.
2626     * @apiBody {Boolean} [avatar_flg=false] Indicates if the request is for avatar lessons.
2627     * 
2628     * @apiSuccess {Boolean} res Indicates whether the request was successful.
2629     * @apiSuccess {Object[]} lessonHistory The list of lesson history.
2630     * @apiSuccess {Number} lessonHistory.lesson_number The lesson number.
2631     * @apiSuccess {String} lessonHistory.chatStartJPDate The start date of the chat in JP format.
2632     * @apiSuccess {String} lessonHistory.chatStartTime The start time of the chat.
2633     * @apiSuccess {String} lessonHistory.lessonHistoryTime The duration of the lesson.
2634     * @apiSuccess {String} lessonHistory.textbook_url The URL of the textbook.
2635     * @apiSuccess {String} lessonHistory.categoryNameLabel The category name of the textbook.
2636     * @apiSuccess {String} lessonHistory.subCategoryNameLabel The subcategory name of the textbook.
2637     * @apiSuccess {String} lessonHistory.textbookNameLabel The name of the textbook.
2638     * @apiSuccess {Number} lessonHistory.rate The rating of the lesson.
2639     * @apiSuccess {String} lessonHistory.chat_logs_url The URL of the chat logs.
2640     * @apiSuccess {Boolean} lessonHistory.has_message_logs Indicates if the lesson has message logs.
2641     * @apiSuccess {String} lessonHistory.message_logs_url The URL of the message logs.
2642     * @apiSuccess {Number} lessonHistory.audio_count_log The audio count log.
2643     * @apiSuccess {String} lessonHistory.textbook_image The image URL of the textbook.
2644     *
2645     * @apiSuccessExample {json} Success-Response:
2646     *     {
2647     *         "res": true,
2648     *         "lessonHistory": [
2649     *             {
2650     *                 "lesson_number": 1,
2651     *                 "chatStartJPDate": "2023-12-01",
2652     *                 "chatStartTime": "10:00",
2653     *                 "lessonHistoryTime": "30分",
2654     *                 "textbook_url": "/textbook/page-detail/1/123",
2655     *                 "categoryNameLabel": "Category Name",
2656     *                 "subCategoryNameLabel": "Subcategory Name",
2657     *                 "textbookNameLabel": "Textbook Name",
2658     *                 "rate": 5,
2659     *                 "chat_logs_url": "/chat-history/123/abc123",
2660     *                 "has_message_logs": true,
2661     *                 "message_logs_url": "/lesson-message/detail/1",
2662     *                 "audio_count_log": 3,
2663     *                 "textbook_image": "http://example.com/image.jpg"
2664     *             }
2665     *         ]
2666     *     }
2667     *
2668     * @apiError {Boolean} res Indicates whether the request was successful.
2669     *
2670     * @apiErrorExample {json} Error-Response:
2671     *     {
2672     *         "res": false
2673     *     }
2674     * 
2675     * @apiSampleRequest off
2676     */
2677    public function getLessonHistory($sp = false, $teacherId = null) {
2678        $this->autoRender = false;
2679        $this->layout = false;
2680        $response = json_encode(array('res' => false)); // default
2681        
2682        if($this->request->is('post') || $sp) {
2683            $post = $this->request->data;
2684            if (!isset($post['teacherId']) && $post['teacherId']) {
2685                return json_encode($response);
2686            }
2687            $teacherId = $post['teacherId'] ?? $teacherId;
2688            $teacherId = Sanitize::escape($teacherId);
2689
2690            $isAvatarFlg = (isset($post['avatar_flg']) && $post['avatar_flg']) ? true : false;
2691
2692            //NC-7984 start
2693            if($isAvatarFlg){
2694                $lesson_history_data = $this->LessonSchedule->latestLessonHistory($teacherId, $this->Auth->user('id'), $this->localizeDir, 10, "avatar");
2695            }else{
2696                $lesson_history_data = $this->LessonSchedule->latestLessonHistory($teacherId, $this->Auth->user('id'), $this->localizeDir, 10);
2697
2698            }
2699
2700            if(!empty($lesson_history_data) && $lesson_history_data) {
2701                $textbookNamesCachedArr = $lesson_history_data['textbookNamesCachedArr'];
2702
2703                foreach ($lesson_history_data['lessonHistory'] as $key => $value) {
2704                    $dteStart = new DateTime($value['LessonOnairsLog']['start_time']);
2705                    $dteEnd   = new DateTime($value['LessonOnairsLog']['end_time']);
2706
2707                    $logDetail = new LessonOnairsLogTable($value['LessonOnairsLog']);
2708
2709                    $lessonTime = $dteStart->diff($dteEnd);
2710                    $lessonHistoryTime = $lessonTime->format("%I");
2711
2712                    $textbookOrder = isset($textbookNamesCachedArr[$value['TextbookConnect']['id']]['order']) ? $textbookNamesCachedArr[$value['TextbookConnect']['id']]['order'] : '';
2713
2714                    $categoryName = $value['TextbookCategory']['name'];
2715                    $subcategoryName = $value['TextbookSubategory']['name'];
2716                    $textbookName = $value['Textbook']['name'];
2717                    $textbookMainTopicName = isset($value['Textbook']['main_topic_name']) ? $value['Textbook']['main_topic_name'] : '';
2718
2719                    // - if has translated Category name
2720                    if (isset($value['GlobalTextbookCategory']['gl_name']) && $value['GlobalTextbookCategory']['gl_name']) {
2721                        $categoryName = $value['GlobalTextbookCategory']['gl_name'];
2722                    }
2723
2724                    // - if has translated subcategory name
2725                    if (isset($value['GlobalTextbookSubcategory']['gl_name']) && $value['GlobalTextbookSubcategory']['gl_name']) {
2726                        $subcategoryName = $value['GlobalTextbookSubcategory']['gl_name'];
2727                    }
2728
2729                    // - if has translated textbook name
2730                    if (isset($value['GlobalTextbook']['gl_name']) && $value['GlobalTextbook']['gl_name']) {
2731                        $textbookName = $value['GlobalTextbook']['gl_name'];
2732                    }
2733
2734                    // - set textbook name
2735                    $categoryNameLabel = $categoryName;
2736                    $subCategoryNameLabel = $subcategoryName;
2737                    $subCategoryNameLabel = $textbookMainTopicName ? $textbookMainTopicName : $subcategoryName;
2738                    $textbookNameLabel = $textbookOrder . $textbookName;
2739                    $textbook_url = "/textbook/page-detail/{$value['TextbookCategory']['type_id']}/{$value['LessonOnairsLog']['connect_id']}";
2740
2741                    $has_message_logs = !empty($value['LessonOnairsLog']['lesson_memo']) && $value['LessonOnairsLog']['lesson_memo_disp_flg'] == 1 && $value['LessonOnairsLog']['display_message'] == 1;
2742                    $message_logs_url = "/lesson-message/detail/{$value['LessonOnairsLog']['id']}";
2743                    $teacher_id = $value['LessonOnairsLog']['teacher_id'];
2744                    $chat_logs_url = "/chat-history/{$teacher_id}/{$value['LessonOnairsLog']['chat_hash']}";
2745
2746                    $lesson_history_data['lessonHistory'][$key]['lesson_number'] = $value['LessonTrackLogs']['lesson_number'];
2747                    $lesson_history_data['lessonHistory'][$key]['chatStartJPDate'] = $logDetail->chatStartJPDate($this->timeDiffSecond);
2748                    $lesson_history_data['lessonHistory'][$key]['chatStartTime'] = $logDetail->chatStartTime($this->timeDiffSecond);
2749                    $lesson_history_data['lessonHistory'][$key]['lessonHistoryTime'] = $lessonHistoryTime. __('分');
2750                    $lesson_history_data['lessonHistory'][$key]['textbook_url'] = $textbook_url;
2751                    $lesson_history_data['lessonHistory'][$key]['categoryNameLabel'] = $categoryNameLabel;
2752                    $lesson_history_data['lessonHistory'][$key]['subCategoryNameLabel'] = $subCategoryNameLabel;
2753                    $lesson_history_data['lessonHistory'][$key]['textbookNameLabel'] = $textbookNameLabel;
2754                    $lesson_history_data['lessonHistory'][$key]['rate'] = $value['usersClassEvaluations']['rate'];
2755                    $lesson_history_data['lessonHistory'][$key]['chat_logs_url'] = $chat_logs_url;
2756                    $lesson_history_data['lessonHistory'][$key]['has_message_logs'] = $has_message_logs;
2757                    $lesson_history_data['lessonHistory'][$key]['message_logs_url'] = $message_logs_url;
2758                    $lesson_history_data['lessonHistory'][$key]['audio_count_log'] = $value['LessonOnairsLog']['temp_flg1'];
2759                    $lesson_history_data['lessonHistory'][$key]['textbook_image'] = $value['TextbookCategory']['image_big_url'];
2760                }
2761                
2762                $response = json_encode(array(
2763                    'res' => true, 
2764                    'lessonHistory' => $lesson_history_data['lessonHistory']
2765                ));
2766
2767                if($sp) {
2768                    $response = $lesson_history_data['lessonHistory'];
2769                }
2770            }
2771            //NC-7984 end
2772        }
2773
2774        return $response;
2775
2776    }
2777
2778    /**
2779     * @api {post} /user/waiting/getPrimaryDetails getPrimaryDetails()
2780     * @apiName getPrimaryDetails
2781     * @apiGroup Waiting
2782     * @apiDescription Retrieves the primary details for a specific teacher in Native Camp. It returns the number of lessons, reservations, and comments for the teacher.
2783     *
2784     * @apiBody {String} teacherId The ID of the teacher.
2785     * 
2786     * @apiSuccess {Number} lessonCount The number of lessons for the teacher.
2787     * @apiSuccess {Number} reserveCount The number of reservations for the teacher.
2788     * @apiSuccess {Number} commentCount The number of comments for the teacher.
2789     *
2790     * @apiSuccessExample {json} Success-Response:
2791     *     {
2792     *         "lessonCount": 100,
2793     *         "reserveCount": 50,
2794     *         "commentCount": 20
2795     *     }
2796     *
2797     * @apiError {String} status The status of the request (NG).
2798     * @apiError {String} message The error message.
2799     *
2800     * @apiErrorExample {json} Error-Response:
2801     *     {
2802     *         "status": "NG",
2803     *         "message": "Invalid request."
2804     *     }
2805     * 
2806     * @apiSampleRequest off
2807     */
2808    public function getPrimaryDetails() {
2809        $this->autoRender = false;
2810        $this->layout = "";
2811        if (!$this->request->is('ajax')) { return ; }
2812        
2813        $teacherId = $this->request->data['teacherId'];
2814        $teacherId = Sanitize::escape($teacherId);
2815        
2816        if (empty($teacherId)) { return ; }
2817
2818        //number of lesson for all child accounts
2819        $lessonCount = $this->LessonOnairsLog->countTeacherLessons(['teacherId' => $teacherId, 'avatar' => 1]);
2820        //number of reservation for all child accounts
2821        $reserveCount = $this->LessonSchedule->countTeacherReservedLessons(array('teacherId' => $teacherId, 'avatar' => 1));
2822
2823        $options = $this->Auth->user('id') ? array('userId' => $this->Auth->user('id')) : array();
2824        $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir,true);
2825        $options['language_id'] = $reviewLanguage[0];
2826        $options['not_language_ids'] = $reviewLanguage[1] ?? null;
2827        $options['isAvatar'] = 1;
2828
2829        $userTable = new UserTable($this->Auth->user());
2830        $sapuriPlan = $userTable->isStudySapuri();
2831        $sapuriTextbookType = Configure::read('all_sapuri_textbook_category_types');
2832        if ($this->isStudySapuriUser && isset($sapuriTextbookType[$sapuriPlan])) {
2833            $options['textbook_category_type'] = $sapuriTextbookType[$sapuriPlan];
2834        } else {
2835            $options['textbook_category_type_not_in'] = $sapuriTextbookType;
2836        }
2837
2838        $commentCount = $this->UsersClassEvaluation->getCommentCount($teacherId, $options);
2839        $results = [
2840            'lessonCount' => $lessonCount,
2841            'reserveCount' => $reserveCount,
2842            'commentCount' => $commentCount,
2843        ];
2844
2845        echo json_encode($results);
2846        return;
2847    }
2848
2849    /**
2850     * @api {post} /user/waiting/getFavCount getFavCount()
2851     * @apiName getFavCount
2852     * @apiGroup Waiting
2853     * @apiDescription Retrieves the favorite count for a specific teacher in Native Camp. It returns the total number of favorites and whether the current user has favorited the teacher.
2854     *
2855     * @apiBody {String} teacherId The ID of the teacher.
2856     * 
2857     * @apiSuccess {Boolean} res Indicates whether the request was successful.
2858     * @apiSuccess {Number} favCount The total number of favorites for the teacher.
2859     * @apiSuccess {Number} isFav Indicates whether the current user has favorited the teacher (1: Yes, 0: No).
2860     *
2861     * @apiSuccessExample {json} Success-Response:
2862     *     {
2863     *         "res": true,
2864     *         "favCount": 10,
2865     *         "isFav": 1
2866     *     }
2867     *
2868     * @apiError {Boolean} res Indicates whether the request was successful.
2869     *
2870     * @apiErrorExample {json} Error-Response:
2871     *     {
2872     *         "res": false
2873     *     }
2874     * 
2875     * @apiSampleRequest off
2876     */
2877    public function getFavCount() {
2878        $this->autoRender = false;
2879        $this->layout = false;
2880        $response = json_encode(array('res' => false)); // default
2881
2882        if($this->request->is('post')) {
2883            $post = $this->request->data;
2884            if (!isset($post['teacherId']) && $post['teacherId']) {
2885                return json_encode($response);
2886            }
2887            $teacherId = $post['teacherId'];
2888
2889            $favCount = $this->UsersFavorite->find('count', array(
2890                'conditions' => array(
2891                    'UsersFavorite.teacher_id'  => $teacherId
2892                )
2893            ));
2894
2895            $isFav = $this->UsersFavorite->find('count', array(
2896                'conditions' => array(
2897                    'UsersFavorite.user_id'     => $this->Auth->user('id'),
2898                    'UsersFavorite.teacher_id'     => $teacherId,
2899                )
2900            ));
2901
2902            if ($favCount){
2903                $response = json_encode(array('res' => true, 'favCount' => $favCount, 'isFav' => $isFav));
2904            }
2905        }
2906        return $response;
2907    }
2908
2909    /**
2910     * @api {post} /user/waiting/getAlbum getAlbum()
2911     * @apiName getAlbum
2912     * @apiGroup Waiting
2913     * @apiDescription Retrieves the album of images for a specific teacher in Native Camp. It returns the list of approved images for the teacher.
2914     *
2915     * @apiBody {String} teacherId The ID of the teacher.
2916     * 
2917     * @apiSuccess {Boolean} res Indicates whether the request was successful.
2918     * @apiSuccess {Object[]} [albums] The list of albums (only if the request was successful).
2919     * @apiSuccess {Number} albums.id The ID of the teacher image.
2920     * @apiSuccess {Number} albums.teacher_id The ID of the teacher.
2921     * @apiSuccess {Number} albums.approve_flg The approval flag of the image.
2922     * @apiSuccess {Number} albums.is_profile Indicates if the image is a profile image.
2923     * @apiSuccess {Number} albums.approve_required Indicates if the image requires approval.
2924     * @apiSuccess {String} albums.url The URL of the image.
2925     *
2926     * @apiSuccessExample {json} Success-Response:
2927     *     {
2928     *         "res": true,
2929     *         "albums": [
2930     *             {
2931     *                 "id": 1,
2932     *                 "teacher_id": 123,
2933     *                 "approve_flg": 1,
2934     *                 "is_profile": 0,
2935     *                 "approve_required": 0,
2936     *                 "url": "http://example.com/image.jpg"
2937     *             }
2938     *         ]
2939     *     }
2940     *
2941     * @apiError {Boolean} res Indicates whether the request was successful.
2942     *
2943     * @apiErrorExample {json} Error-Response:
2944     *     {
2945     *         "res": false
2946     *     }
2947     * 
2948     * @apiSampleRequest off
2949     */
2950    public function getAlbum() {
2951        $this->autoRender = false;
2952        $this->layout = false;
2953        $response = json_encode(array('res' => false)); // default
2954
2955        if($this->request->is('post')) {
2956            $post = $this->request->data;
2957            if (!isset($post['teacherId']) && $post['teacherId']) {
2958                return json_encode($response);
2959            }
2960            $teacherId = $post['teacherId'];
2961
2962            $this->TeacherImage->openDBReplica();
2963            $album = $this->TeacherImage->find('all', array(
2964                'fields' => array(
2965                    'TeacherImage.id',
2966                    'TeacherImage.teacher_id',
2967                    'TeacherImage.approve_flg',
2968                    'TeacherImage.is_profile',
2969                    'TeacherImage.approve_required',
2970                    'FileStorage.url'
2971                ),
2972                'conditions' => array(
2973                    'TeacherImage.teacher_id' => $teacherId,
2974                    'TeacherImage.is_profile' => 0,
2975                    'OR' => array(
2976                        'OR' => array(
2977                            'TeacherImage.approve_flg' => 1,
2978                            'TeacherImage.approve_required' => 0,
2979                        )
2980                    )
2981                ),
2982                'joins' => array(
2983                    array(
2984                        'type' => 'INNER',
2985                        'table' => 'file_storage',
2986                        'alias' => 'FileStorage',
2987                        'conditions' => array(
2988                            'TeacherImage.file_storage_id = FileStorage.id',
2989                            'FileStorage.uploader_type = 3',
2990                            'FileStorage.uploader_id' => $teacherId
2991                        )
2992                    )
2993                ),
2994                'order' => array('TeacherImage.id DESC')
2995            ));
2996            $this->TeacherImage->closeDBReplica();
2997
2998            if ($album){
2999                $response = json_encode(array('res' => true, 'albums' => $album));
3000            }
3001        }
3002        return $response;
3003    }
3004    
3005
3006    // NJ-3786 - arrange teacher data
3007    private function arrangeTeacherRecommendList( $params = array() ){
3008        $result = array();
3009        $data = isset( $params['data'] ) && $params['data'] ? $params['data'] : null;
3010        $userId = isset( $params['user_id'] ) && $params['user_id'] ? $params['user_id'] : null;
3011        $userData = isset($params['user_data']) && $params['user_data'] ?  $params['user_data'] : null;
3012        $nativeLanguage = isset($userData['native_language2']) && $userData['native_language2'] ?  $userData['native_language2'] : null;
3013        $platformArrangeApiList = (isset($params['platform_arrange']) && $params['platform_arrange'] == 'api') ;
3014        $categoryId = isset($params['category_id']) && $params['category_id'] ?  $params['category_id'] : null;
3015        $classStatusArr = Configure::read('teacher_lamp_color_class');
3016        $textbookImagUrl = null;
3017        if($categoryId){
3018            // Fetch textbook image
3019            $textbookParams = array(
3020                'conditions' => array('TextbookCategory.id' => $categoryId ),
3021                'fields' => array('TextbookCategory.image_big_url'),
3022                'recursive' => -1
3023            );
3024            ClassRegistry::init('TextbookCategory')->openDBReplica();
3025            $fetchTextbookData = ClassRegistry::init('TextbookCategory')->find('first',$textbookParams);
3026            ClassRegistry::init('TextbookCategory')->closeDBReplica();
3027            if($fetchTextbookData && isset($fetchTextbookData['TextbookCategory']['image_big_url']) && $fetchTextbookData['TextbookCategory']['image_big_url'] ){
3028                $textbookImagUrl = $fetchTextbookData['TextbookCategory']['image_big_url'];
3029            }
3030        }
3031
3032        if($data){
3033            foreach( $data as $index => $val ) {
3034                $teacherDetail = new TeacherTable($val['Teacher']);
3035                // - get countries
3036                $countries = strtolower($val['CountryCode']['country_name']);
3037                $explodeCountries = explode(' ', $countries);
3038                $implode = implode('_',$explodeCountries);
3039
3040                // - country name
3041                $countryName = $val['CountryCodeDetails']['country_name'] ? $val['CountryCodeDetails']['country_name'] : $val['CountryCode']['country_name'];
3042
3043                // - get residency
3044                $recidency = strtolower($countryName);
3045                $explodeRecidency = explode(' ', $recidency);
3046                $implodeResidency = implode('_',$explodeRecidency);
3047
3048                // - nationality
3049                $arrNationalityInfo = array(
3050                    "id" => "",
3051                    "name" => $val['CountryCode']['country_name'],
3052                    "flag" => $implode
3053                );
3054
3055                // - residence info
3056                $arrResidenceInfo = array(
3057                    "id" => "",
3058                    "name" => $countryName,
3059                    "flag" => $implodeResidency
3060                );
3061
3062                $getUserSettingLanguage = $nativeLanguage && $nativeLanguage == 'ja' ? $teacherDetail->jp_name : $teacherDetail->name ;
3063
3064                if( $platformArrangeApiList ) {
3065                    $result[$index] = array(
3066                        "id" => $teacherDetail->id,
3067                        "name" => $getUserSettingLanguage,
3068                        "name_ja" => $teacherDetail->jp_name,
3069                        "name_eng" => $teacherDetail->name,
3070                        "rating" => isset($val['TeacherTextbookWeeklyRating']['ratings']) ? number_format((float)$val['TeacherTextbookWeeklyRating']['ratings'], 2, '.', '') : 0,
3071                        "lessons" => isset($val['TeacherTextbookStat']['lesson_count']) ? $val['TeacherTextbookStat']['lesson_count'] : 0,
3072                        "favorite_count" => $this->UsersFavorite->getFavoriteCount($teacherDetail->id),
3073                        "age" => isset($val[0]['Teacher__age']) ? (int)$val[0]['Teacher__age'] : 0,
3074                        "nationality_id" =>(int)$val['CountryCode']['id'],
3075                        "image_main" =>  $teacherDetail->getImageUrl(),
3076                        // - country, residence info
3077                        'residence_image' =>  FULL_BASE_URL."/user/images/flag/".$arrResidenceInfo["flag"].".png",
3078                        'residence_name' => __d('default',$arrResidenceInfo["name"]),
3079                        'country_name' => __d('default',$arrNationalityInfo["name"]),
3080                        'country_image' =>  FULL_BASE_URL."/user/images/flag/".$arrNationalityInfo["flag"].".png",
3081                        'textbook_image_url' =>  $textbookImagUrl
3082                    );
3083                } else {
3084                    $result[$index]['Teacher'] = $val['Teacher'];
3085                    $result[$index]['Teacher']['lesson_count'] = isset($val['TeacherTextbookStat']['lesson_count']) ? $val['TeacherTextbookStat']['lesson_count'] : 0;
3086                    $result[$index]['Teacher']['favorite_count'] = $this->UsersFavorite->getFavoriteCount($teacherDetail->id);
3087                    $result[$index]['Teacher']['age'] = isset($val[0]['Teacher__age']) ? (int)$val[0]['Teacher__age'] : 0;
3088                    $result[$index]['Teacher']['evaluation_average'] = isset($val['TeacherTextbookWeeklyRating']['ratings']) ? number_format((float)$val['TeacherTextbookWeeklyRating']['ratings'], 2, '.', '') : __d('waiting', '集計中');
3089                    $result[$index]['Teacher']['image_url'] = $teacherDetail->getImageUrl();
3090                    $result[$index]['Teacher']['residence_image'] = FULL_BASE_URL."/user/images/flag/".$arrResidenceInfo["flag"].".png";
3091                    $result[$index]['Teacher']['residence_name'] = __d('default',$arrResidenceInfo["name"]);
3092                    $result[$index]['Teacher']['country_name'] = __d('default',$arrNationalityInfo["name"]);
3093                    $result[$index]['Teacher']['country_image'] = FULL_BASE_URL."/user/images/flag/".$arrNationalityInfo["flag"].".png";
3094                    $result[$index]['Teacher']['textbook_image_url'] = $textbookImagUrl;
3095                }
3096            }
3097        }
3098
3099        return $result;
3100
3101    }
3102
3103    //not sued function
3104    public function checkReservation($teacher, $onair_status) {
3105
3106        // 定数 取得 (category=26)
3107        $getDefineMaster = $this->DefineMaster->getDefine('26');
3108        // 入室できる時間(n分前)
3109        $DefinePossible = new DefineMasterTable($getDefineMaster[0]["DefineMaster"]);
3110        // レッスンできる時間(n分前)
3111        $DefineLessonPossible = new DefineMasterTable($getDefineMaster[0]["DefineMaster"]);
3112        $reserver = 0;
3113
3114        $floored_seconds = floor(time() / (30 * 60)) * (30 * 60);
3115        $ceiled_seconds = ceil(time() / (30 * 60)) * (30 * 60);
3116        // 予約状況を取得
3117        $this->LessonSchedule->recursive = -1;
3118        $getLessonSchedule = $this->LessonSchedule->getLessonSchedule(date('Y-m-d H:i:s', $floored_seconds), date('Y-m-d H:i:s', $ceiled_seconds), $teacher->id, 'asc');
3119
3120        // 予約がある
3121        if(!empty($getLessonSchedule)) {
3122            $LessonSchedule = new LessonScheduleTable($getLessonSchedule[0]["LessonSchedule"]);
3123
3124            // 入室できる時間
3125            $possible_time = strtotime("- " . $DefinePossible->contents . " minutes", strtotime($LessonSchedule->lesson_time));
3126
3127            // 予約時間
3128            $reservation_time = strtotime($LessonSchedule->lesson_time);
3129
3130            // レッスン可能な時間($lesson_possible_timeまで)
3131            $lesson_possible_time = strtotime("- " . $DefineLessonPossible->contents . " minutes", strtotime($LessonSchedule->lesson_time));
3132
3133            // 予約しているユーザのID
3134            $userID = $getLessonSchedule[0]['LessonSchedule']["user_id"];  //not used user id . undefined variable $getLessonSchedule
3135
3136            // 予約があっても 定数(category=26, sub_category=1)分前なら入室できる
3137            if(time() <= $possible_time && $onair_status == 1) {
3138                // 予約時間
3139                $this->set('ReservationTime', date('H:i', $reservation_time));
3140                // レッスン可能時間
3141                $this->set('PossibleTime',  date('H:i', $lesson_possible_time));
3142            }
3143
3144            # get minute now
3145            $minuteNow = (int) date("i");
3146
3147            // 予約してる人は自分
3148            if (
3149                $userID == $this->Auth->user('id') &&
3150                $onair_status == 2 &&
3151                !(
3152                    ($minuteNow >= 56 && $minuteNow <= 59) ||
3153                    ($minuteNow >= 26 && $minuteNow <= 29)
3154                )
3155            ) {
3156                $reserver = 1;
3157            }
3158        }
3159
3160        $this->set('isReserved', $reserver);
3161    }
3162
3163    /**
3164     * @api {get} /user/waiting/start/:teacher_id/:free_flg/:class_id/:chapter_id/:textbook_type start()
3165     * @apiName start
3166     * @apiGroup Waiting
3167     * @apiDescription Starts a lesson for a specific teacher and user in Native Camp. It checks various conditions and redirects to the appropriate page.
3168     *
3169     * @apiParam {String} teacher_id The ID of the teacher.
3170     * @apiParam {String} [free_flg=null] The free flag.
3171     * @apiParam {String} [class_id=1] The ID of the class.
3172     * @apiParam {String} [chapter_id=1] The ID of the chapter.
3173     * @apiParam {String} [textbook_type=null] The type of the textbook.
3174     * 
3175     * @apiSuccess {String} redirect_url The URL to which the user is redirected.
3176     *
3177     * @apiSuccessExample {json} Success-Response:
3178     *     {
3179     *         "redirect_url": "/class/index/123/1/1/1/1"
3180     *     }
3181     *
3182     * @apiError {String} status The status of the request (NG).
3183     * @apiError {String} message The error message.
3184     *
3185     * @apiErrorExample {json} Error-Response:
3186     *     {
3187     *         "status": "NG",
3188     *         "message": "Invalid request."
3189     *     }
3190     * 
3191     * @apiSampleRequest off
3192     */
3193    public function start($teacher_id, $free_flg=null, $class_id = null, $chapter_id = null, $textbook_type = null) {
3194        $this->autoRender = false;
3195        App::uses('myTools','Lib');
3196
3197        if (!$class_id)   $class_id     = 1;
3198        if (!$chapter_id) $chapter_id = 1;
3199
3200        if (is_null($teacher_id)) {
3201            return $this->redirect('/waiting/');
3202        }
3203        $data = $this->Teacher->findById($teacher_id);
3204        if (!$data) {
3205            return $this->redirect('/waiting/');
3206        }
3207
3208        /*
3209        * added in issue NC-488
3210        * check whether the user has been blocked already or not
3211        */
3212        //NJ-65055: params for checking teacher is hidden
3213        $isTeacherHiddenParams = array(
3214            'user_id' => $this->Auth->user('id'),
3215            'teacher_id' => $teacher_id
3216        );
3217
3218        if ((BlockListTable::isUserBlocked($this->Auth->User('id'), $teacher_id) == true) || $this->BlockList->isTeacherHide($isTeacherHiddenParams)) {
3219            return $this->redirect('/waiting/'); exit;
3220        }
3221
3222        // onairデータの中の講師IDがない
3223        $onAir = $this->LessonOnair->findByTeacherId($teacher_id);
3224        if (!isset($onAir['LessonOnair'])) {
3225            return $this->redirect('/');
3226        }
3227
3228        // レッスン中の場合
3229        if (!empty($onAir['LessonOnair']['status']) && $onAir['LessonOnair']['status']==3) {
3230            return $this->redirect('/waiting/detail/' . $teacher_id);
3231        }
3232
3233        // Overlapping reservation bug
3234        $lesson_available = $this->LessonSchedule->checkLessonAvailable($this->Auth->user('id'), $teacher_id);
3235        if (!$lesson_available) {
3236            return $this->redirect('/waiting/detail/' . $teacher_id);
3237        }
3238
3239
3240        $onAirId = $onAir['LessonOnair']['id'];
3241
3242        $this->Session->write('proceedFlag.clicked', 'true');
3243        return $this->redirect('/class/index/' . $teacher_id . '/' . $free_flg . '/' . $class_id . '/' . $chapter_id . '/' . $textbook_type);
3244    }
3245
3246    /**
3247     * @api {post} /user/waiting/teacherReserveList teacherReserveList()
3248     * @apiName teacherReserveList
3249     * @apiGroup Waiting
3250     * @apiDescription Retrieves the reservation list for a specific teacher in Native Camp. It returns various information about the available reservation slots, user eligibility, and more.
3251     *
3252     * @apiBody {String} teacherId The ID of the teacher.
3253     * @apiBody {Boolean} [counselingFlg=0] Indicates if the request is for counseling.
3254     * @apiBody {String} [hash16] The hash16 value for the user.
3255     * @apiBody {Number} [timeDiff=0] The time difference in seconds.
3256     * @apiBody {Boolean} [reservationHideFlg=false] Indicates if the reservation slots should be hidden.
3257     * @apiBody {Boolean} [hideLimitedPlanReservation=null] Indicates if the limited plan reservations should be hidden.
3258     * @apiBody {Number} [teacherCoin=0] The coin value for the teacher.
3259     * @apiBody {Number} [sapuriCoin=0] The coin value for Sapuri.
3260     * 
3261     * @apiSuccess {Object[]} days The list of days for the reservation slots.
3262     * @apiSuccess {String} days.Y The year.
3263     * @apiSuccess {String} days.m The month.
3264     * @apiSuccess {String} days.d The day.
3265     * @apiSuccess {String} days.w The day of the week.
3266     * @apiSuccess {String} days.reserve_range The reservation range for the day.
3267     * @apiSuccess {Boolean} days.canUseCoupon Indicates if a coupon can be used for the reservation.
3268     * @apiSuccess {Object[]} times The list of times for the reservation slots.
3269     * @apiSuccess {Object} reserved The reserved slots.
3270     * @apiSuccess {String} user_id The ID of the user.
3271     * @apiSuccess {Number} userCardCompany The card company of the user.
3272     * @apiSuccess {Number} timeDiff The time difference in seconds.
3273     * @apiSuccess {Object} reservedTz The reserved slots with timezone adjustments.
3274     * @apiSuccess {Boolean} limitedPlanAvailable Indicates if the limited plan reservation is available.
3275     * @apiSuccess {Boolean} hideLimitedPlanReservation Indicates if the limited plan reservations should be hidden.
3276     * @apiSuccess {Boolean} notCorporateLightTeachers Indicates if the teacher is not a corporate light teacher.
3277     * @apiSuccess {Boolean} corporateLightUser Indicates if the user is a corporate light user.
3278     * @apiSuccess {Boolean} corporateLimitedUser Indicates if the user is a corporate limited user.
3279     * @apiSuccess {Object} teacherInfo The information of the teacher.
3280     * @apiSuccess {Object} campaignPeriod The campaign period information.
3281     * @apiSuccess {Object} discountCampaignPeriod The discount campaign period information.
3282     * @apiSuccess {String} currentUserTime The current user time.
3283     * @apiSuccess {String} currentUtcOffset The current UTC offset.
3284     * @apiSuccess {Boolean} isShowCancellationAlert Indicates if the cancellation alert should be shown.
3285     * @apiSuccess {Object[]} otherReservations The list of other reservations.
3286     * @apiSuccess {Boolean} viewSlotForSapuri Indicates if the slot is for Sapuri.
3287     * @apiSuccess {String} studySapuriId The ID of the study Sapuri.
3288     * @apiSuccess {Object[]} lessonRequestSlot The list of lesson request slots.
3289     * @apiSuccess {Boolean} lessonRequestInvalidPlan Indicates if the lesson request plan is invalid.
3290     * @apiSuccess {String} teacherId The ID of the teacher.
3291     * @apiSuccess {Number} callanOption Indicates if the Callan option is available.
3292     * @apiSuccess {Object} user The user information.
3293     * @apiSuccess {Object} teacherData The teacher data.
3294     * @apiSuccess {String[]} weekday The list of weekdays.
3295     * @apiSuccess {Object} hiddenReservedTz The hidden reserved slots with timezone adjustments.
3296     * @apiSuccess {Boolean} canLive Indicates if the user can join live lessons.
3297     * @apiSuccess {Boolean} normalLitePlanCanReserveFlg Indicates if the normal lite plan can reserve.
3298     * @apiSuccess {Boolean} isNormalLitePlan Indicates if the user is on a normal lite plan.
3299     * @apiSuccess {Boolean} notNormalLitePlanTeacher Indicates if the teacher is not a normal lite plan teacher.
3300     * @apiSuccess {Boolean} teacherCoinDisableSlots Indicates if the teacher coin disables slots.
3301     * @apiSuccess {Boolean} excludeLessonRequestDiscount Indicates if the lesson request discount should be excluded.
3302     * @apiSuccess {Number} lessonRequestFlg The lesson request flag.
3303     * @apiSuccess {Boolean} notNewCampaignEligible Indicates if the user is not eligible for the new campaign.
3304     * @apiSuccess {String} teacherImageSrc The image URL of the teacher.
3305     * @apiSuccess {String} teacherName The name of the teacher.
3306     *
3307     * @apiSuccessExample {json} Success-Response:
3308     *     {
3309     *         "days": [
3310     *             {
3311     *                 "Y": "2023",
3312     *                 "m": "12",
3313     *                 "d": "01",
3314     *                 "w": "(金)",
3315     *                 "reserve_range": "10:00~11:00",
3316     *                 "canUseCoupon": true
3317     *             }
3318     *         ],
3319     *         "times": ["10:00", "10:30", "11:00"],
3320     *         "reserved": {...},
3321     *         "user_id": "123",
3322     *         "userCardCompany": 1,
3323     *         "timeDiff": 0,
3324     *         "reservedTz": {...},
3325     *         "limitedPlanAvailable": true,
3326     *         "hideLimitedPlanReservation": false,
3327     *         "notCorporateLightTeachers": false,
3328     *         "corporateLightUser": true,
3329     *         "corporateLimitedUser": false,
3330     *         "teacherInfo": {...},
3331     *         "campaignPeriod": {...},
3332     *         "discountCampaignPeriod": {...},
3333     *         "currentUserTime": "2023/12/01 10:00",
3334     *         "currentUtcOffset": "+09:00",
3335     *         "isShowCancellationAlert": true,
3336     *         "otherReservations": [...],
3337     *         "viewSlotForSapuri": true,
3338     *         "studySapuriId": "sapuri123",
3339     *         "lessonRequestSlot": [...],
3340     *         "lessonRequestInvalidPlan": false,
3341     *         "teacherId": "456",
3342     *         "callanOption": 1,
3343     *         "user": {...},
3344     *         "teacherData": {...},
3345     *         "weekday": ["(日)", "(月)", "(火)", "(水)", "(木)", "(金)", "(土)"],
3346     *         "hiddenReservedTz": {...},
3347     *         "canLive": true,
3348     *         "normalLitePlanCanReserveFlg": true,
3349     *         "isNormalLitePlan": true,
3350     *         "notNormalLitePlanTeacher": false,
3351     *         "teacherCoinDisableSlots": false,
3352     *         "excludeLessonRequestDiscount": false,
3353     *         "lessonRequestFlg": 1,
3354     *         "notNewCampaignEligible": false,
3355     *         "teacherImageSrc": "http://example.com/image.jpg",
3356     *         "teacherName": "John Doe"
3357     *     }
3358     *
3359     * @apiError {String} status The status of the request (NG).
3360     * @apiError {String} message The error message.
3361     *
3362     * @apiErrorExample {json} Error-Response:
3363     *     {
3364     *         "status": "NG",
3365     *         "message": "Invalid request."
3366     *     }
3367     * 
3368     * @apiSampleRequest off
3369     */
3370    public function teacherReserveList() {
3371        $this->layout = "";
3372
3373        if (!$this->request->is('post')) {
3374            return ;
3375        }
3376
3377        $data = $this->request->data;
3378        $teacherId = isset($data['teacherId']) ? $data['teacherId'] : null;
3379        $counselingFlg = isset($data['counselingFlg']) ? $data['counselingFlg'] : 0;
3380        $hash16 = isset($data['hash16']) ? $data['hash16'] : null;
3381        $timeDiff = isset($data['timeDiff']) ? $data['timeDiff'] : 0;
3382        $reservationHideFlg = isset($data['reservationHideFlg']) ? $data['reservationHideFlg'] : false;
3383        $hideLimitedPlanReservation = isset($data['hideLimitedPlanReservation']) ? $data['hideLimitedPlanReservation'] : null;
3384        $teacherCoin = isset($data['teacherCoin']) ? $data['teacherCoin'] : 0;
3385        $sapuriCoin = isset($data['sapuriCoin']) ? $data['sapuriCoin'] : 0;
3386        $viewSlotForSapuri = false;
3387
3388        if (empty($teacherId)) {
3389            return ;
3390        }
3391
3392        $userId = $this->Auth->user('id');
3393        $teacher = ClassRegistry::init('Teacher')->getTeacherInfo($teacherId);
3394        $teacherInfo = $teacher['Teacher'];
3395        $userLanguage =  !empty($this->Auth->user('native_language2')) ? $this->Auth->user('native_language2') :Configure::read('default.user_language');
3396
3397        $this->User->recursive = -1;
3398        $user = $this->User->findById($userId);
3399
3400        // NJ-18780 : set var if callan half price teacher 
3401        $_isCallanHalfTeacher = (int) $teacherInfo['callan_halfprice_flg'];
3402
3403        if (
3404            $this->sharedUserData && 
3405            $this->isStudySapuriUser && 
3406            $sapuriCoin && 
3407            $teacherCoin <= $sapuriCoin
3408        ) {
3409            $viewSlotForSapuri = true;
3410            $userObj = new UserTable($this->sharedUserData['User']);
3411            $plan = $userObj->isStudySapuri();
3412            
3413            //NJ-10847 Hide Slots if Teacher has no Sapuri Textbook Badge
3414            $badgeParams = array('plan' => $plan, 'teacher_id' => $teacherId);
3415            $badges = TeacherBadgeTable::getSapuriStudentAndTeacherBadge($badgeParams);
3416            if (!$badges) {
3417                $viewSlotForSapuri = false;
3418            }
3419        }
3420
3421        // Hide reservations slot if lite plan and reservation coin is 0 
3422        if (in_array($user['User']['payment_plan_id'],Configure::read('lite_payment_plans')) && $teacherCoin <= 0) {
3423            $reservationHideFlg = true;
3424        }
3425
3426        $isCorporateUser = isset($this->sharedUserData['User']) && !empty($this->sharedUserData['User']['corporate_id']);
3427        $forceFetchCampaignPeriod = $isCorporateUser || $this->isStudySapuriUser;
3428
3429        $times = array();
3430        $utcMin = explode(':', $this->utcOffset);
3431        if ($utcMin[1] == "45") {
3432            for ($i=0; $i<=23; $i++) {
3433                $times[] = sprintf("%02d",$i) . ':15';
3434                $times[] = sprintf("%02d",$i) . ':45';
3435            }
3436        } else {
3437            for ($i=0; $i<=23; $i++) {
3438                $times[] = sprintf("%02d",$i) . ':00';
3439                $times[] = sprintf("%02d",$i) . ':30';
3440            }
3441        }
3442
3443        $days = array();
3444
3445        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) { // if the language is Custom language format
3446            $weekday = array( __dx('waiting', 'day_three_letter', '(日)'), __dx('waiting', 'day_three_letter','(月)'), __dx('waiting', 'day_three_letter','(火)'), __dx('waiting', 'day_three_letter','(水)'), __dx('waiting', 'day_three_letter','(木)'), __dx('waiting', 'day_three_letter','(金)'), __dx('waiting', 'day_three_letter','(土)') );
3447        } else { // if the language is not Custom language format
3448            $weekday = array( __d('waiting','(日)'), __d('waiting','(月)'), __d('waiting','(火)'), __d('waiting','(水)'), __d('waiting','(木)'), __d('waiting','(金)'), __d('waiting','(土)') );
3449        }
3450
3451        $reserved = array();
3452        // if reservation_hide_flg, display open reservation slots
3453        
3454        // 予約状況を取得
3455        // ~ hide slots if teacher reservation hide flg is true
3456        if (!$reservationHideFlg) {
3457            $reserved = $this->LessonSchedule->findReserveListByTeacherIdAndLessondate(
3458                $userId,
3459                $teacherId,
3460                date('Ymd', time()),
3461                date('Ymd', strtotime("+8 days", time())),
3462                false,
3463                $reservationHideFlg
3464            );
3465        }
3466
3467        // // overide reserved for campaign hide slots for not eligeble users
3468        // if ($reservationCampaignHideFlg && isset($campaignDiscountFlg) && $campaignDiscountFlg) {
3469        //     $reserved = $this->LessonSchedule->findReserveListByTeacherIdAndLessondate(
3470        //         $userId,
3471        //         $teacherId,
3472        //         date('Ymd', strtotime($campaignDiscountFlg['CampaignInstructor']['start_date'])),
3473        //         date('Ymd', strtotime($campaignDiscountFlg['CampaignInstructor']['end_date'])),
3474        //         false,
3475        //         $reservationCampaignHideFlg
3476        //     );
3477        // }
3478        
3479        // if have own reserved or available slot, check for live lesson slot
3480        $liveShift = array();
3481        $liveShiftLessonTimeData = [];
3482        if ($reserved) {
3483            $this->ShiftWorkOn->openDBReplica();
3484            $liveShift = $this->ShiftWorkOn->find('all', array(
3485                'fields' => ['ShiftWorkOn.lesson_time','DATE_FORMAT(ShiftWorkOn.lesson_time, \'%Y%m%d%H%i%S\') AS time'],
3486                'conditions' => array(
3487                    'ShiftWorkOn.teacher_id' => $teacherId,
3488                    'ShiftWorkOn.live_lesson_flg' => 1,
3489                    'ShiftWorkOn.hide_flg' => 0,
3490                    'ShiftWorkOn.lesson_time >= NOW()'
3491                ),
3492                'recursive' => -1
3493            ));
3494            $this->ShiftWorkOn->closeDBReplica();
3495
3496            $canLive = true;
3497            if ($liveShift) {
3498                if ($this->sharedUserData) {
3499                    $canLive = UserTable::canDoLiveViewing($this->sharedUserData['User']);
3500                }
3501                foreach ($liveShift as $shift) {
3502
3503                    if( isset($shift['ShiftWorkOn']['lesson_time']) && $shift['ShiftWorkOn']['lesson_time'] ) {
3504                        $liveShiftLessonTimeData[] = $shift['ShiftWorkOn']['lesson_time'];
3505                    }
3506
3507                    if ( empty($reserved[$shift[0]['time']]) ) {
3508                        continue;
3509                    }
3510
3511                    //-- open for live lesson resevation
3512                    if ( $reserved[$shift[0]['time']] == 9 ) {
3513                        if (!$canLive) {
3514                            unset($reserved[$shift[0]['time']]);     //-- hide live lesson for invalid member
3515                        } else {
3516                            $reserved[$shift[0]['time']] = 10;         //-- available live
3517                        }
3518
3519                    //-- own live lesson reservation
3520                    } elseif ( $reserved[$shift[0]['time']] == 2 ) {
3521                        $reserved[$shift[0]['time']] = 11;
3522
3523                    //-- other student live lesson reservation
3524                    } elseif ( $reserved[$shift[0]['time']] == 1 ) {
3525                        if (!$canLive) {
3526                            unset($reserved[$shift[0]['time']]);     //-- hide live lesson for invalid member
3527                        } else {
3528                            $reserved[$shift[0]['time']] = 12;         //-- reserved by another
3529                        }
3530                    }
3531                }
3532            }
3533        }
3534
3535        // Check if sapuri user and with in campaign's duration (sicth anniv, christmas)
3536        $ifSapuriAndCampaign = false;
3537        $sixthAnnivCampaignDateArr = Configure::read('campaign_config.sixth_anniv_1.period');
3538        // $christmasDateArr = Configure::read('campaign_config.christmas.period');
3539        // $goldenWeekDateArr = Configure::read('campaign_config.christmas.period');
3540        if (
3541            (
3542                (time() >= strtotime($sixthAnnivCampaignDateArr['start']) && time() <= strtotime($sixthAnnivCampaignDateArr['end']))
3543                // || (time() >= strtotime($christmasDateArr['start']) && time() <= strtotime($christmasDateArr['end']))
3544                // || (time() >= strtotime($goldenWeekDateArr['start']) && time() <= strtotime($goldenWeekDateArr['end']))
3545            )
3546            && $this->studySapuriId
3547        ) {
3548            $ifSapuriAndCampaign = true;
3549        }
3550        $isCorporateUser = isset($this->sharedUserData['User']) && !empty($this->sharedUserData['User']['corporate_id']);
3551        $forceFetchCampaignPeriod = $isCorporateUser || $this->isStudySapuriUser;
3552
3553        //campaign period start and end time
3554        $campaignPeriod = null;
3555        if (($reserved && !$ifSapuriAndCampaign) || $forceFetchCampaignPeriod) {
3556            $campaignPeriod = $this->PopularTeacherCampaignPeriod->fetchCampaignPeriod(array(
3557                'user_id' => $this->Auth->user('id'),
3558                'teacher_id' => $teacherId,
3559                'bypass_count' => $forceFetchCampaignPeriod
3560            ));
3561        }
3562
3563        if (($reserved && !$ifSapuriAndCampaign) || $forceFetchCampaignPeriod) {
3564            $discountcampaignPeriod = $this->CampaignInstructor->fetchNewCampaignPeriod(array(
3565                'user_id' => $this->Auth->user('id'),
3566                'teacher_id' => $teacherId,
3567                'bypass_count' => $forceFetchCampaignPeriod
3568            ));
3569        }
3570
3571        //NJ-28004 get current reservation
3572        $currentReseervations = $this->LessonSchedule->getCurrentTeacherReservation($teacherId, $userId);
3573
3574        //NC-3787 - get all users reservation except for current teacher
3575        $otherReservations = $this->LessonSchedule->getOtherReservationsExcept($teacherId, $userId);
3576        $reservedDate = '';
3577        $reservedTz = array();
3578        $teacherData = array();
3579        $reservedArr = is_array($reserved) ? $reserved : [];
3580
3581        $allLessonTimes = array_unique(array_merge(
3582            array_map(function($reservedData) {
3583                return date('Y-m-d H:i:s', strtotime($reservedData));
3584            }, array_keys($reservedArr)),
3585            $otherReservations,
3586            $currentReseervations
3587        ));
3588
3589        $allLessonTimes = is_array($allLessonTimes) ? $allLessonTimes : [];
3590        $lessonTimesParams = array(
3591            'lesson_times' => $allLessonTimes,
3592            'teacher_id' => $teacherId,
3593            'user_id' => $userId,
3594            'localize_dir' => $this->localizeDir,
3595            'campaign' => $discountcampaignPeriod
3596        );
3597
3598        $allReservationsData = $this->LessonSchedule->getAllReservationData($lessonTimesParams);
3599
3600        if (is_iterable($reserved)) {
3601            foreach($reserved as $key => $val) {
3602
3603                $teacherSlotEvent = Configure::read('reservation_event_type.normal');
3604                $reservedLessonTime = date('Y-m-d H:i:s', strtotime($key));
3605                $campaignPeriod['lesson_time'] = $reservedLessonTime;
3606                $discountcampaignPeriod['lesson_time'] = $reservedLessonTime;
3607                $inCampaign = false;
3608                $inNewCampaign = false;
3609
3610                if ($this->CampaignInstructor->checkCampaignPeriod($discountcampaignPeriod)) {
3611                    $inNewCampaign = true;
3612                }
3613
3614                if ($this->CampaignInstructor->checkCampaignPeriod($discountcampaignPeriod)) {
3615                    $inNewCampaign = true;
3616                }
3617
3618                if( $liveShiftLessonTimeData && in_array($reservedLessonTime,$liveShiftLessonTimeData) ) {
3619                    $teacherSlotEvent = Configure::read('reservation_event_type.live_lesson');
3620                } elseif( $inCampaign ) {
3621                    $teacherSlotEvent = Configure::read('reservation_event_type.popular_campaign');
3622                }elseif( $inNewCampaign ) {
3623                    $teacherSlotEvent = Configure::read('reservation_event_type.discount_campaign');
3624                }
3625
3626                $teacherData = in_array($reservedLessonTime, $otherReservations) ? ($allReservationsData[$reservedLessonTime] ?? []) : [];
3627                $currentTeacherData = in_array($reservedLessonTime, $currentReseervations) ? ($allReservationsData[$reservedLessonTime] ?? []) : [];
3628
3629                $reservedDatas = [
3630                    'reserved' => $key,
3631                    'val' => $val,
3632                    'reservation_event' => $teacherSlotEvent,
3633                    'teacherData' => $teacherData,
3634                    'currentTeacherData' => $currentTeacherData
3635                ];
3636
3637                $timeKeySlot = TimezoneTable::computeTimeToUser(array('time' => strtotime($key), 'timestamp' => $this->timeDiffSecond, 'format' => 'YmdHis'));
3638                $reservedTz[$timeKeySlot] = $reservedDatas;
3639
3640                $currentDate = substr($key, 0,8);
3641                $min = date('i', strtotime($key));
3642                $hour = intval(date('H', strtotime($key)));
3643                if ($min == '30') {
3644                    $hour = $hour + 1;
3645                    $min = ":00";
3646                } else {
3647                    $min = ":30";
3648                }
3649                if ($reservedDate != $currentDate) {
3650                    if (!isset($reservedRange[$currentDate][0])) {
3651                        $reservedRange[$currentDate][0] = date('H:i', strtotime($key));
3652                        $reservedRange[$currentDate][1] = strval($hour).$min;
3653                    } else {
3654                        $reservedRange[$currentDate][1] = strval($hour).$min;
3655                    }
3656                } else {
3657                    $reservedRange[$currentDate][1] = strval($hour).$min;
3658                }
3659                $rKeys = array_keys($reservedRange);
3660                $rLastKey = end($rKeys);
3661                $reservedDate = $rLastKey;
3662
3663            }
3664        }
3665
3666        if (is_iterable($otherReservations)) {
3667            foreach($otherReservations as $key => $val) {
3668                $teacherSlotEvent = Configure::read('reservation_event_type.normal');
3669                $timeKeySlot = TimezoneTable::computeTimeToUser(array('time' => strtotime($val), 'timestamp' => $this->timeDiffSecond, 'format' => 'YmdHis'));
3670                $reservedLessonTime = date('Y-m-d H:i:s', strtotime($val));
3671
3672                // - do nothing - avoid conflict
3673                if (isset($reservedTz[$timeKeySlot])) {
3674                    continue;
3675                }
3676
3677                // - set reservation info
3678                $teacherData = $allReservationsData[$reservedLessonTime] ?? [];
3679                $currentTeacherData = $allReservationsData[$reservedLessonTime] ?? [];
3680
3681                // - set reservation data
3682                $reservedDatas = [
3683                    'reserved' => $val,
3684                    'val' => [],
3685                    'reservation_event' => $teacherSlotEvent,
3686                    'teacherData' => $teacherData,
3687                    'currentTeacherData' => $currentTeacherData
3688                ];
3689
3690                // - set reserved TZ
3691                $reservedTz[$timeKeySlot] = $reservedDatas;
3692            }
3693        }
3694
3695        $coupon = false;
3696        $couponDateCanUse = date('Y-m-d');
3697        $ccPeriod = false;
3698        if (!is_null($hash16)) {
3699            $freeTicket = false;
3700            if(PaymentTable::checkIfPaidUser($userId, $hash16)) {
3701                $freeTicket = true;
3702            } elseif (PaymentTable::checkIfCardAuth($userId, $hash16)) {
3703                $freeTicket = true;
3704            }
3705
3706            if ($freeTicket) {
3707                // check if can use coupon for reservation
3708                $coupon = ClassRegistry::init('UserCoupon')->canUseCoupon($userId);
3709                // get last coupon date used
3710                $couponDateCanUse = ClassRegistry::init('UserCoupon')->getDateCouponCanUse($userId);
3711
3712                // check if coupon campaign period
3713                $ccPeriod = myTools::couponCampaignPeriod();
3714            }
3715        }
3716        for ($i=0; $i<=7; $i++) {
3717            $cTime = strtotime("+" . $i . " days", $this->displayTime);
3718            $canUseCoupon = false;
3719            if (
3720                $couponDateCanUse && $coupon && $ccPeriod && !$counselingFlg
3721                && strtotime(date('Y-m-d', $cTime)) >= strtotime($couponDateCanUse)
3722            ) {
3723                $canUseCoupon = true;
3724            }
3725            $resRange = (isset($reservedRange[date('Ymd', $cTime)]))?$reservedRange[date('Ymd', $cTime)][0].'~'.$reservedRange[date('Ymd', $cTime)][1]:'';
3726            $days[] = array(
3727                'Y' => date('Y', $cTime),
3728                'm' => date('m', $cTime),
3729                'd' => date('d', $cTime),
3730                'w' => $weekday[date("w", $cTime)],
3731                'reserve_range' => $resRange,
3732                'canUseCoupon' => $canUseCoupon
3733            );
3734        }
3735
3736        // NC-4546 - check phone verification auth
3737        $verifyCount = $this->PhoneVerifyCheckLog->find('count',array(
3738            'conditions' => array(
3739                'user_id' => $this->Auth->User('id'),
3740                'status' => 0
3741            )
3742        ));
3743        $notCorporateLightTeachers = false;
3744        $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($user['User']['payment_plan_id'] );
3745
3746        if ( isset($corporateType) && $corporateType == Configure::read("corporate_type.light") ) {
3747            $checkCorpLightTeacher = ClassRegistry::init('Teacher')->corporateLightTeacher($teacherId);
3748            if (!$checkCorpLightTeacher) {
3749                $notCorporateLightTeachers = true;
3750            }
3751        }
3752
3753
3754        $grc = $this->getReserveAndCancelled($teacherId);
3755        $isShowCancellationAlert = $grc['this_month_cancellation_rate'] >= Configure::read('alert_cancellation_rate') ? true : false;
3756
3757        $limitedPlanAvailable = false;
3758
3759        // if user is corporate limited check if limited plan reservation is ON
3760        if ($corporateType == Configure::read("corporate_type.limited")) {
3761            $this->TeacherRankCoin->openDBReplica();
3762            $teacherRankCoin = $this->TeacherRankCoin->find('first', array(
3763                'fields' => array('TeacherRankCoin.limited_plan_reservation'),
3764               'conditions' => array('TeacherRankCoin.id' => $teacher['Teacher']['rank_coin_id'])
3765            ));
3766            $this->TeacherRankCoin->closeDBReplica();
3767
3768            $teacherRankCoin = $teacherRankCoin ? $teacherRankCoin['TeacherRankCoin'] : false;
3769            $limitedPlanAvailable = $teacherRankCoin && $teacherRankCoin['limited_plan_reservation'];
3770        }
3771        
3772        $callan_unlimited_flg = 0;
3773
3774
3775        # NJ-19429: check if teacher is in campaign
3776        if(
3777            (isset($user['User']['callan_option']) && $user['User']['callan_option'])
3778            ||
3779            (isset($user['User']['native_option']) && $user['User']['native_option'])
3780        ) {
3781            // - check existing reservation
3782            $has_callan_option_reserved = $this->LessonSchedule->hasCallanOptionReserved($userId);
3783            
3784            if($has_callan_option_reserved == 0) {
3785                // - check teacher callan option
3786                $unlimited_option_flag = $this->HomeBasedRankBasicAmount->getUnlimitedOptionFlg($teacherInfo['current_rank_id']);
3787                $callan_unlimited_flg = (isset($unlimited_option_flag['callan_unlimited_option_flg']) && $unlimited_option_flag['callan_unlimited_option_flg']) ? 1 : 0;
3788            }
3789        }
3790        
3791        #NJ-18780:set to allow normal lite plan to reserve
3792        $normalLitePlanCanReserveFlg = true;
3793        $isNormalLitePlan = false;
3794        $notNormalLitePlanTeacher = false;
3795
3796        $lessonRequestSlot = array();
3797
3798        if($this->isStudySapuriTosUser) {
3799            $lessonRequestSlot = array();            
3800        } else if (in_array($user['User']['payment_plan_id'],Configure::read('lite_payment_plans')) && $teacherCoin <= 0) {
3801            $lessonRequestSlot = array();
3802        } else {
3803            //-- lesson request schedule
3804
3805            // - NJ-46366: prefetch lesson request slot
3806            $prefetchStart = date("Y-m-d 00:00:00");
3807            $prefetchEnd = date("Y-m-d 23:59:59", strtotime("+7 day"));
3808
3809            $prefetchedUserReservationData = $this->LessonSchedule->getReservationData(
3810                ['startDate' => $prefetchStart, 
3811                'endDate' => $prefetchEnd], 
3812                $user['User']['id'],
3813                $userLanguage
3814            );
3815    
3816            $prefetchedUsersCancelledReservationData = $this->LessonScheduleCancel->hasSlotBeenCancelled([
3817                'user_id' => $user['User']['id'],
3818                'lesson_time' => [
3819                    'startDate' => $prefetchStart, 
3820                    'endDate' => $prefetchEnd
3821                ]
3822            ]);
3823            
3824            $lessonRequestSlot = $this->LessonSchedule->lessonRequestSlotDetail(array(
3825                'user_id' => $userId,
3826                'teacher_id' => $teacherId,
3827                'timeDiffSecond' => $this->timeDiffSecond,
3828                'user_language' => $this->localizeDir,
3829                'campaign' => $discountcampaignPeriod,
3830                'userReservationData' => $prefetchedUserReservationData,
3831                'cancelledReservationData' => $prefetchedUsersCancelledReservationData
3832            ));
3833
3834            //-override hide dates or closed slots fetch reservation data
3835            $hiddenReservedTz = [];
3836            $resData = $this->LessonSchedule->getHiddenReservation([
3837                'user_id' => $userId
3838            ]);
3839
3840            if ($resData) {
3841                foreach ($resData as $key => $row) {
3842                    $lessonReqquestSlotData = $this->LessonSchedule->getReservationData($key, $userId, $this->localizeDir);
3843                    if (!empty($lessonReqquestSlotData)) {
3844                        $lessonReqquestSlotData['icon_color'] = $this->LessonSchedule->getIconColor($lessonReqquestSlotData, $key);
3845                        $hiddenReservedTz[TimezoneTable::computeTimeToUser(array('time' => strtotime($key), 'timestamp' => $this->timeDiffSecond, 'format' => 'YmdHis'))] = $lessonReqquestSlotData;
3846                    }
3847                }
3848            }
3849        }
3850
3851        $membershipStatusIndex = UserTable::getStudentMembershipStatus($this->Auth->User('id'));
3852        $CampaignEligible = $this->CampaignInstructor->verifyStudentMembership($this->Auth->User('id'));
3853        $isNotNewCampaignEligible = !$CampaignEligible['verified'];
3854
3855        // NJ-33414
3856        $this->UsersDetail->openDBReplica();
3857        $fetchUsersDetail = $this->UsersDetail->find('first', array(
3858            'fields' => array(
3859                'user_id',
3860                'lesson_request_flg'
3861            ),
3862            'conditions' =>  array('user_id' => $userId),
3863            'recursive' => -1
3864        ));
3865        $this->UsersDetail->closeDBReplica();
3866        // - check if light plan and over ride to allow reserve on live lesson
3867        if (in_array($user['User']['payment_plan_id'],Configure::read('lite_payment_plans'))) {
3868            # not allow user to reserve live lesson
3869            $canLive = false;
3870        
3871            #set to normal lite plan user
3872            $isNormalLitePlan = true;
3873        
3874            #count the total upcoming reservation limited only to 1 reservation ?
3875            $liteUserReservationCount = $this->LessonSchedule->countUserTotalReservation(array('userId' => $userId));
3876        
3877            if ($liteUserReservationCount >= Configure::read("lite_plan_maximum_number_of_total_reservation")) {
3878                # not allow to reserve any more
3879                $normalLitePlanCanReserveFlg = false;
3880            }
3881
3882            // - check if teacher is callan half price
3883            if ($_isCallanHalfTeacher == 1 && empty($campaign)) {
3884                $notNormalLitePlanTeacher = true;
3885
3886                // - hide slots for lesson request 
3887                $lessonRequestSlot =  array();
3888            }
3889        }
3890
3891        //NJ-19429: teacher coin in slot restriction
3892        $teacherCoinDisableSlots = false;
3893        if($teacherCoin > 100){
3894            $isSlotReserveDisabled = in_array($membershipStatusIndex, Configure::read('slots_disabled_membership'));
3895            if($isSlotReserveDisabled){
3896                $lessonRequestSlot = array();
3897                $teacherCoinDisableSlots = true;
3898            }
3899        }
3900
3901        // NJ-47838 : check if live lesson callan discount campaign is enabled 
3902        $isLiveDiscountCallanCampaignCount = ClassRegistry::init('CampaignTagControl')->checkTeacherLiveCallanTag($discountcampaignPeriod['campaign_tag_id']);
3903        $excludeLessonRequestDiscount ??= '';
3904        $this->set(array(
3905            'smsThroughFlg' => isset($user['User']['sms_through_flg']) ? $user['User']['sms_through_flg'] : false,
3906            'verifyCount' => $verifyCount,
3907            'days' => $days,
3908            'times' => $times,
3909            'reserved' => $reserved,
3910            'user_id' => ($this->Auth->loggedIn()) ? $userId : null,
3911            'userCardCompany' => isset($user['User']['card_company']) ? $user['User']['card_company'] : 0,
3912            'timeDiff' => $timeDiff,
3913            'reservedTz' => $reservedTz,
3914            'limitedPlanAvailable' => $limitedPlanAvailable,
3915            'hideLimitedPlanReservation' => $hideLimitedPlanReservation,
3916            'notCorporateLightTeachers' => $notCorporateLightTeachers,
3917            'corporateLightUser' => ($corporateType == Configure::read("corporate_type.light")),
3918            'corporateLimitedUser' => ($corporateType == Configure::read("corporate_type.limited")),
3919            'teacherInfo' => $teacherInfo,
3920            'campaignPeriod' => $campaignPeriod,
3921            'discountCampaignPeriod' => $discountcampaignPeriod,
3922            'currentUserTime' => date(
3923                isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support")) ? 
3924                'd/m/Y G:i' : 'Y/m/d G:i', 
3925                $this->displayTime
3926            ),
3927            'currentUtcOffset' => $this->utcOffset,
3928            'isShowCancellationAlert' => $isShowCancellationAlert,
3929            'otherReservations' => $otherReservations,
3930            'viewSlotForSapuri' => $viewSlotForSapuri,
3931            'studySapuriId' => $this->studySapuriId,
3932            'lessonRequestSlot' => $lessonRequestSlot,
3933            'lessonRequestInvalidPlan' => in_array($membershipStatusIndex, [12, 13]),
3934            'teacherId' => $teacherId,
3935            'callanOption' => $callan_unlimited_flg,
3936            'user' => $user,
3937            'teacherData' => $teacherInfo,
3938            'weekday' => $weekday,
3939            'hiddenReservedTz' => $hiddenReservedTz,
3940            'canLive' => $canLive,
3941            'normalLitePlanCanReserveFlg' => $normalLitePlanCanReserveFlg,
3942            'isNormalLitePlan' => $isNormalLitePlan,
3943            'notNormalLitePlanTeacher' => $notNormalLitePlanTeacher,
3944            'teacherCoinDisableSlots' => $teacherCoinDisableSlots,
3945            'excludeLessonRequestDiscount'=> $excludeLessonRequestDiscount ? true : false,
3946            'lessonRequestFlg' => $fetchUsersDetail ? (int)$fetchUsersDetail['UsersDetail']['lesson_request_flg'] : 1,   // NJ-33414
3947            'notNewCampaignEligible' => $isNotNewCampaignEligible,
3948            'isLiveDiscountCallanCampaignCount' => $isLiveDiscountCallanCampaignCount
3949        ));
3950
3951        // get teacher information
3952        $teacher = new TeacherTable($teacherInfo);
3953        $teacherImageSrc = $teacher->getImageUrl();
3954        $teacherName = $teacher->getName();
3955        $this->set('teacherImageSrc', $teacherImageSrc);
3956        $this->set('teacherName', $teacherName);
3957
3958        $this->render('teacher_reserve_list_new');
3959
3960    }
3961
3962    //not used function
3963    public function updateChapterOptions() {
3964        $this->autoRender = false;
3965        $classId = $this->request->data['classid'];
3966        $teacherId = $this->request->data['teacherid'];
3967
3968        if (isset($this->request->data['firstid'])) {
3969            $firstId = $this->request->data['firstid'];
3970        } else {
3971            $firstId = '';
3972        }
3973
3974        if (isset($this->request->data['lastid'])) {
3975            $lastId = $this->request->data['lastid'];
3976        } else {
3977            $lastId = '';
3978        }
3979        return $this->result($teacherId, $classId, $firstId, $lastId);
3980    }
3981
3982    /**
3983     * @api {post} /user/waiting/result/:teacherId/:classId/:firstId/:lastId result()
3984     * @apiName result
3985     * @apiGroup Waiting
3986     * @apiDescription Retrieves the list of chapters for a specific class and teacher in Native Camp. It returns the updated list of chapters along with the first and last chapter IDs.
3987     *
3988     * @apiParam {String} teacherId The ID of the teacher.
3989     * @apiParam {String} classId The ID of the class.
3990     * @apiParam {String} [firstId] The ID of the first chapter.
3991     * @apiParam {String} [lastId] The ID of the last chapter.
3992     * 
3993     * @apiSuccess {Object[]} chapterList The list of chapters.
3994     * @apiSuccess {String} chapterList.UsersLastViewedTextbook.last_viewed_date The last viewed date of the chapter.
3995     * @apiSuccess {String} chapterList.LessonText.chapter_id The ID of the chapter.
3996     * @apiSuccess {String} chapterList.LessonText.chapter The name of the chapter.
3997     * @apiSuccess {String} firstChapter The ID of the first chapter.
3998     * @apiSuccess {String} lastChapter The ID of the last chapter.
3999     * @apiSuccess {String} teacherId The ID of the teacher.
4000     * @apiSuccess {String} classId The ID of the class.
4001     * @apiSuccess {Object} lastViewedTextInfo The information of the last viewed text.
4002     * @apiSuccess {String} lastViewedTextInfo.UsersLastViewedTextbook.last_viewed_date The last viewed date of the text.
4003     * @apiSuccess {String} lastViewedTextInfo.UsersLastViewedTextbook.class_id The ID of the class.
4004     * @apiSuccess {String} lastViewedTextInfo.UsersLastViewedTextbook.chapter_id The ID of the chapter.
4005     * @apiSuccess {String} lastViewedTextInfo.UsersLastViewedTextbook.preset Indicates if the text is preset.
4006     * @apiSuccess {String} userId The ID of the user.
4007     *
4008     * @apiSuccessExample {json} Success-Response:
4009     *     {
4010     *         "chapterList": [
4011     *             {
4012     *                 "UsersLastViewedTextbook": {
4013     *                     "last_viewed_date": "2023-12-01 10:00:00"
4014     *                 },
4015     *                 "LessonText": {
4016     *                     "chapter_id": "1",
4017     *                     "chapter": "Chapter 1"
4018     *                 }
4019     *             }
4020     *         ],
4021     *         "firstChapter": "1",
4022     *         "lastChapter": "10",
4023     *         "teacherId": "123",
4024     *         "classId": "456",
4025     *         "lastViewedTextInfo": {
4026     *             "UsersLastViewedTextbook": {
4027     *                 "last_viewed_date": "2023-12-01 10:00:00",
4028     *                 "class_id": "456",
4029     *                 "chapter_id": "1",
4030     *                 "preset": "0"
4031     *             }
4032     *         },
4033     *         "userId": "789"
4034     *     }
4035     *
4036     * @apiError {String} status The status of the request (NG).
4037     * @apiError {String} message The error message.
4038     *
4039     * @apiErrorExample {json} Error-Response:
4040     *     {
4041     *         "status": "NG",
4042     *         "message": "Invalid request."
4043     *     }
4044     * 
4045     * @apiSampleRequest off
4046     */
4047    public function result($teacherId, $classId, $firstId, $lastId) {
4048        $user_id = $this->Auth->user('id');
4049        if ($lastId != '') {
4050            $lastId = $this->request->data['lastid'];
4051            $classChapterList = $this->LessonText->find('all',
4052                array(
4053                    'joins' => array(
4054                        array(
4055                            'type'  => 'LEFT',
4056                            'table' => 'users_last_viewed_textbooks',
4057                            'alias' => 'UsersLastViewedTextbook',
4058                            'conditions' => array(
4059                                'UsersLastViewedTextbook.user_id    = ' . $user_id,
4060                                'UsersLastViewedTextbook.class_id   = LessonText.class_id',
4061                                'UsersLastViewedTextbook.chapter_id = LessonText.chapter_id',
4062                                'UsersLastViewedTextbook.preset !=' => 1
4063                            )
4064                        )
4065                    ),
4066                    'fields' => array(
4067                        'UsersLastViewedTextbook.last_viewed_date',
4068                        'LessonText.chapter_id',
4069                        'LessonText.chapter'
4070                    ),
4071                    'conditions' => array(
4072                        'LessonText.class_id' => $classId,
4073                        'LessonText.chapter_id >' => $lastId,
4074                        'LessonText.status' => 1
4075                    ),
4076                    'order' => 'ISNULL(LessonText.orderno), LessonText.orderno ASC, LessonText.chapter_id ASC'
4077                )
4078            );
4079
4080        } else if ($firstId != '') {
4081            $firstId = $this->request->data['firstid'];
4082            $classChapterList = $this->LessonText->find('all',
4083                array(
4084                    'joins' => array(
4085                        array(
4086                            'type'  => 'LEFT',
4087                            'table' => 'users_last_viewed_textbooks',
4088                            'alias' => 'UsersLastViewedTextbook',
4089                            'conditions' => array(
4090                                'UsersLastViewedTextbook.user_id    = ' . $user_id,
4091                                'UsersLastViewedTextbook.class_id   = LessonText.class_id',
4092                                'UsersLastViewedTextbook.chapter_id = LessonText.chapter_id',
4093                                'UsersLastViewedTextbook.preset !=' => 1
4094                            )
4095                        )
4096                    ),
4097                    'fields' => array(
4098                        'UsersLastViewedTextbook.last_viewed_date',
4099                        'LessonText.chapter_id',
4100                        'LessonText.chapter'
4101                    ),
4102                    'conditions' => array(
4103                        'LessonText.class_id' => $classId,
4104                        'LessonText.chapter_id <' => $firstId,
4105                        'LessonText.status' => 1
4106                    ),
4107                    'order' => 'ISNULL(LessonText.orderno), LessonText.orderno ASC, LessonText.chapter_id ASC'
4108                )
4109            );
4110        } else {
4111
4112            $classChapterList = $this->LessonText->find('all',
4113                array(
4114                    'joins' => array(
4115                        array(
4116                            'type'  => 'LEFT',
4117                            'table' => 'users_last_viewed_textbooks',
4118                            'alias' => 'UsersLastViewedTextbook',
4119                            'conditions' => array(
4120                                'UsersLastViewedTextbook.user_id    = ' . $user_id,
4121                                'UsersLastViewedTextbook.class_id   = LessonText.class_id',
4122                                'UsersLastViewedTextbook.chapter_id = LessonText.chapter_id',
4123                                'UsersLastViewedTextbook.preset !=' => 1
4124                            )
4125                        )
4126                    ),
4127                    'fields' => array(
4128                        'UsersLastViewedTextbook.last_viewed_date',
4129                        'LessonText.class_id',
4130                        'LessonText.chapter_id',
4131                        'LessonText.chapter'
4132                    ),
4133                    'conditions' => array(
4134                        'LessonText.class_id' => $classId,
4135                        'LessonText.status' => 1
4136                    ),
4137                    'order' => 'ISNULL(LessonText.orderno), LessonText.orderno ASC, LessonText.chapter_id ASC'
4138                )
4139            );
4140        }
4141
4142        $classChapterFirstLast = $this->LessonText->find('first',
4143            array(
4144                'conditions' => array(
4145                    'LessonText.class_id' => $classId
4146                ),
4147                'fields' => array(
4148                    'MIN(LessonText.chapter_id) as first_chapter',
4149                    'MAX(LessonText.chapter_id) as last_chapter'
4150                )
4151            )
4152        );
4153
4154        if ($classChapterFirstLast) {
4155            $this->set('firstChapter', $classChapterFirstLast[0]['first_chapter']);
4156            $this->set('lastChapter', $classChapterFirstLast[0]['last_chapter']);
4157        } else {
4158            $this->set('firstChapter', '');
4159            $this->set('lastChapter', '');
4160        }
4161
4162        $this->set('teacherId', $teacherId);
4163        $this->set('classId', $classId);
4164        if ($firstId != '') {
4165            $classChapterList = array_reverse($classChapterList);
4166        }
4167
4168        //NC-634
4169        $lastViewedText = $this->UsersLastViewedTextbook->find(
4170            'all',
4171            array(
4172                'conditions' => array(
4173                    'UsersLastViewedTextbook.user_id' => $user_id,
4174                    'UsersLastViewedTextbook.preset !=' => 1
4175                ),
4176                'order' => array('UsersLastViewedTextbook.modified DESC'),
4177                'limit' => 1
4178            )
4179        );
4180
4181        $lastViewedTextInfo = array();
4182        if(isset($lastViewedText[0]) && isset($lastViewedText[0]['UsersLastViewedTextbook'])) {
4183            $lastViewedTextInfo = $lastViewedText[0];
4184        }
4185
4186        $this->set('lastViewedTextInfo', $lastViewedTextInfo);
4187        $this->set('chapterList', $classChapterList);
4188        $this->set('userId', $this->Auth->user('id'));
4189        $this->render('result', 'ajax');
4190    }
4191
4192    /**
4193     * @api {post} /user/waiting/loadMoreComments loadMoreComments()
4194     * @apiName loadMoreComments
4195     * @apiGroup Waiting
4196     * @apiDescription Loads more comments for a specific teacher or counselor in Native Camp. It returns the list of comments and indicates if there are more pages available.
4197     *
4198     * @apiBody {Number} page The page number to load.
4199     * @apiBody {String} teacherId The ID of the teacher.
4200     * @apiBody {Boolean} [isCounseling=false] Indicates if the request is for counseling comments.
4201     * @apiBody {Boolean} [isAvatar=false] Indicates if the request is for avatar comments.
4202     * @apiBody {Number} [order=0] The order of the comments.
4203     * 
4204     * @apiSuccess {Object[]} results The list of comments.
4205     * @apiSuccess {Number} results.id The ID of the comment.
4206     * @apiSuccess {String} results.star The HTML content for the star rating.
4207     * @apiSuccess {Number} results.age The age of the user who made the comment.
4208     * @apiSuccess {String} results.gender The gender of the user who made the comment.
4209     * @apiSuccess {String} results.user_comment The comment text.
4210     * @apiSuccess {String} results.date The date of the comment.
4211     * @apiSuccess {Object} results.textbook The textbook information.
4212     * @apiSuccess {String} results.textbook.textUrl The URL of the textbook.
4213     * @apiSuccess {String} results.textbook.textbook_image The image URL of the textbook.
4214     * @apiSuccess {String} results.textbook.textbook_name_lv1 The level 1 name of the textbook.
4215     * @apiSuccess {String} results.textbook.textbook_name_lv2 The level 2 name of the textbook.
4216     * @apiSuccess {String} results.textbook.textbook_name_lv3 The level 3 name of the textbook.
4217     * @apiSuccess {Number} results.review_id The ID of the review.
4218     * @apiSuccess {Number} results.like_total The total number of likes for the comment.
4219     * @apiSuccess {Number} results.dislike_total The total number of dislikes for the comment.
4220     * @apiSuccess {Number} results.voted Indicates if the user has voted on the comment (0: No, 1: Yes).
4221     * @apiSuccess {Boolean} lastPage Indicates if there are no more pages of comments available.
4222     *
4223     * @apiSuccessExample {json} Success-Response:
4224     *     {
4225     *         "results": [
4226     *             {
4227     *                 "id": 1,
4228     *                 "star": "<div>Star Rating</div>",
4229     *                 "age": 25,
4230     *                 "gender": "Male",
4231     *                 "user_comment": "Great lesson!",
4232     *                 "date": "2023-12-01",
4233     *                 "textbook": {
4234     *                     "textUrl": "http://example.com/textbook",
4235     *                     "textbook_image": "http://example.com/image.jpg",
4236     *                     "textbook_name_lv1": "Level 1",
4237     *                     "textbook_name_lv2": "Level 2",
4238     *                     "textbook_name_lv3": "Level 3"
4239     *                 },
4240     *                 "review_id": 1,
4241     *                 "like_total": 10,
4242     *                 "dislike_total": 2,
4243     *                 "voted": 1
4244     *             }
4245     *         ],
4246     *         "lastPage": false
4247     *     }
4248     *
4249     * @apiError {String} status The status of the request (NG).
4250     * @apiError {String} message The error message.
4251     *
4252     * @apiErrorExample {json} Error-Response:
4253     *     {
4254     *         "status": "NG",
4255     *         "message": "Invalid request."
4256     *     }
4257     * 
4258     * @apiSampleRequest off
4259     */
4260    public function loadMoreComments() {
4261            $this->autoRender = false;
4262            $this->layout = false;
4263            $userId = $this->Auth->user('id');
4264            if ($this->request->is('ajax')) {
4265                $perPage = 4;
4266                $data = $this->request->data;
4267
4268                // - if ajax is from counseling
4269                if (isset($data['isCounseling']) && $data['isCounseling']) {
4270                    $data['teacherId'] = $this->Teacher->getCounselorId();
4271                }
4272
4273                $params = array(
4274                    'order' => isset($data['order']) ? $data['order'] : 0,
4275                    'limit' => $perPage,
4276                    'offset' => $data['page'] * $perPage,
4277                    'userId' => $this->Auth->user('id') ? $this->Auth->user('id') : '',
4278                    'nc_terminal_type' => Configure::read('nc_terminal_type.pc'),
4279                    'lang' => $this->localizeDir
4280                );
4281                $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir);
4282                $options['language_id'] = $reviewLanguage[0];
4283                $options['not_language_ids'] = $reviewLanguage[1] ?? null;
4284                $options['isAvatar'] = ( isset($data['isAvatar']) ) ? 1 : 0 ;
4285                $commentCount = $this->UsersClassEvaluation->getCommentCount($data['teacherId'], $options);
4286
4287                if (isset($data['isAvatar'])) {
4288                    $avatarParams = array(
4289                        'order' => isset($data['order']) ? $data['order'] : 0,
4290                        'limit' => $perPage,
4291                        'offset' => $data['page'] * $perPage,
4292                        'user_id' => $this->Auth->user('id') ? $this->Auth->user('id') : '',
4293                        'nc_terminal_type' => Configure::read('nc_terminal_type.pc'),
4294                        'selfReviewsFlg' => false,
4295                        'avatar_id' => isset($data['teacherId']) ? $data['teacherId'] : 0,
4296                        'lang' => $this->localizeDir
4297                    );
4298
4299                    myTools::initializeApiTunnel(array('AvatarTeacherController'));
4300                    $teachersReviews = new AvatarTeacherController();
4301                    $comments = $teachersReviews->getAllAvatarEvaluation($avatarParams);
4302                    //count avatar reviews
4303                    $commentCount = $teachersReviews->getCountAllEvaluation(array("avatar_id" => isset($data['teacherId']) ? $data['teacherId'] : 0, 'lang' => $this->localizeDir));
4304
4305                } elseif ( isset($data['isCounseling']) ) {
4306                    myTools::initializeApiTunnel(array('TeachersCounselorReviewsController'));
4307                    $teachersReviews = new TeachersCounselorReviewsController();
4308                    $teachersReviews->params = $params;
4309                    $comments = $teachersReviews->getAllCounselEvaluation();
4310                // office teacher
4311                } else {
4312                    myTools::initializeApiTunnel(array('TeachersReviewsController'));
4313                    $teachersReviews = new TeachersReviewsController();
4314                    $params['conditions'] = array(
4315                        'UsersClassEvaluation.teacher_id' => $data['teacherId'],
4316                        'UsersClassEvaluation.approve_flag' => 1,
4317                        'UsersClassEvaluation.user_comment <>' => ''
4318                    );
4319                    $teachersReviews->params = $params;
4320                    $comments = $teachersReviews->getReviews();
4321                }
4322
4323
4324                // - if ajax is from counseling
4325                $view = new View($this, false);
4326                $ctr = 0;
4327                foreach ($comments as $comment) {
4328                    $user = new UserTable($comment['User']);
4329                    $review = new UsersClassEvaluationTable($comment['UsersClassEvaluation']);
4330                    $results[$ctr] = array(
4331                        'id' => $review->id,
4332                        'star' => $view->element('rate', array('rate' => $review->rate)),
4333                        'age' => $user->getAge(),
4334                        'gender' => $user->getGenderComment(),
4335                        'user_comment' => $review->getUserComment(),
4336                        'date' => date('Y-m-d', strtotime($review->getCreatedDate($this->timeDiffSecond)))
4337                    );
4338
4339                    $textbook = $comment['SubTextBook'] ?? null;
4340                    if ($textbook) {
4341                        $notSapuriTextFlg = false;
4342                        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))){
4343                            $pathLocale = '/'. $this->localizeDir;
4344                        }
4345                        $curTextType = $textbook['textbook_category_type'];
4346                        $textDefaultUrl = $pathLocale."/textbook/page-detail/".$textbook['textbook_category_type_id']."/".$textbook['textbook_connect_id'];
4347                        if (isset($this->studySapuriId)) {
4348                            $notSapuriTextFlg = (isset($this->sapuriTextTypes) && $curTextType != $this->sapuriTextTypes) ? true : false;
4349                        }
4350
4351                        $textbook['textUrl'] = $notSapuriTextFlg ? "javascript:void(0)" : $textDefaultUrl;
4352                        $textbook['textbook_image'] = $textbook['textbook_image'] ?? 'no_image';
4353
4354                        if (empty($textbook['textbook_connect_id'])) {
4355                            $textbook['textUrl'] = 'javascript:void(0)';
4356                            $textbook['textbook_image'] = 'no_image';
4357                            $textbook['textbook_name_lv1'] = '';
4358                            $textbook['textbook_name_lv2'] = '';
4359                            $textbook['textbook_name_lv3'] = '';
4360                        }
4361                    }
4362                    $results[$ctr]['textbook'] = $textbook;
4363
4364                    if ($userId) {
4365                        $results[$ctr]['review_id']  = $review->id;
4366                        $results[$ctr]['like_total'] = $review->like_votes;
4367                        $results[$ctr]['dislike_total'] = $review->dislike_votes;
4368                        $results[$ctr]['voted'] = $comment['UsersReviewVote']['vote'] != '' ? (int)$comment['UsersReviewVote']['vote'] : 0;
4369                    }
4370
4371                    $ctr++;
4372                }
4373            }
4374            $lastPage = (intval($data['page'] * $perPage) + $perPage) >= $commentCount ? true : false;
4375            $this->output($results, $lastPage);
4376        }
4377
4378
4379    private function output($data, $lastPage, $result = 'ok') {
4380        $result = array(
4381                'data' => $data,
4382                'result' => $result,
4383                'lastPage' => $lastPage,
4384            );
4385        echo json_encode($result);
4386        exit;
4387    }
4388
4389    /**
4390      * @api {get} /user/waiting/is-can-cancel isCanCancel()
4391      * @apiName isCanCancel
4392      * @apiGroup Waiting
4393      * @apiDescription Checks if the user can cancel a reservation in Native Camp. It returns the status of the cancellation eligibility.
4394      *
4395      * @apiBody {String} [userId] The ID of the user (optional if fromCorporateManagement or fromSapuriTos is set).
4396      * @apiBody {Boolean} [fromCorporateManagement] Indicates if the request is from corporate management.
4397      * @apiBody {Boolean} [fromSapuriTos] Indicates if the request is from Sapuri TOS.
4398      * 
4399      * @apiSuccess {Boolean} canCancel Indicates whether the user can cancel the reservation.
4400      *
4401      * @apiSuccessExample {json} Success-Response:
4402      *     {
4403      *         "canCancel": true
4404      *     }
4405      *
4406      * @apiError {String} status The status of the request (NG).
4407      * @apiError {String} message The error message.
4408      *
4409      * @apiErrorExample {json} Error-Response:
4410      *     {
4411      *         "status": "NG",
4412      *         "message": "Invalid request."
4413      *     }
4414      * 
4415      * @apiSampleRequest off
4416      */
4417    public function isCanCancel() {
4418        $this->autoRender = false;
4419        $get = $this->request->query;
4420
4421        // NC-8336
4422        if (
4423            isset($get['userId']) &&
4424            (isset($get['fromCorporateManagement']) || isset($get['fromSapuriTos']))
4425        ) {
4426            // get user data
4427            $this->User->openDBReplica();
4428            $user = $this->User->find('first', [
4429                'conditions' => ['User.id' => $get['userId']],
4430                'recursive' => -1
4431            ]);
4432            $this->User->closeDBReplica();
4433            $user = $user ? $user['User'] : [];
4434        } else {
4435            $get['userId'] = $this->Auth->user('id');
4436            $user = $this->sharedUserData['User'];
4437        }
4438
4439        $get['nc_terminal_type'] = 1; // pc
4440        $get['timeDiffSecond'] = $this->timeDiffSecond;
4441        $get['localizeDir'] = $this->localizeDir;
4442        $get['user'] = $user;
4443
4444        // open tunnel
4445        myTools::initializeApiTunnel(['ReservationController']);
4446
4447        // initialize controller
4448        $rc = new ReservationController();
4449
4450        // set data
4451        $rc->params = $get;
4452
4453        // process
4454        return $rc->isCanCancel();
4455    }
4456
4457    /**
4458     * @api {get} /user/waiting/convertString convertString()
4459     * @apiName convertString
4460     * @apiGroup Waiting
4461     * @apiDescription Converts a given string by disabling HTML tags and returns the result along with an ID name.
4462     *
4463     * @apiBody {String} _string The string to be converted.
4464     * @apiBody {String} id_name The ID name to be returned.
4465     * 
4466     * @apiSuccess {Object} result The result object.
4467     * @apiSuccess {String} result.res The converted string with HTML tags disabled.
4468     * @apiSuccess {String} result.idName The ID name.
4469     *
4470     * @apiSuccessExample {json} Success-Response:
4471     *     {
4472     *         "res": "Converted string",
4473     *         "idName": "exampleId"
4474     *     }
4475     *
4476     * @apiError {String} status The status of the request (NG).
4477     * @apiError {String} message The error message.
4478     *
4479     * @apiErrorExample {json} Error-Response:
4480     *     {
4481     *         "status": "NG",
4482     *         "message": "Invalid request."
4483     *     }
4484     * 
4485     * @apiSampleRequest off
4486     */
4487    public function convertString() {
4488        $this->autoRender = false;
4489        $string = $this->request->query['_string'];
4490        $idName = $this->request->query['id_name'];
4491        return json_encode(array('res' => myTools::disableHTMLTags($string), 'idName' => $idName));
4492    }
4493
4494    //not used function
4495    public function getTextbookOption($flag = '') {
4496        $this->autoRender = false;
4497        $result = array();
4498        $textbook_type = 0;
4499        $lessonNowReservation = false;
4500        $textbook_category_type = 0;
4501        $lesson_text_id = 0;
4502
4503        $userId = $this->Auth->user('id');
4504        $teacherId = $this->request->data['teacher_id'];
4505
4506        // NJ-9489 : check if membership is allowed to display counselor information
4507        $_userPaymentPlan = $this->sharedUserData['User']['payment_plan_id'];
4508        $hideCouselorFromMember = 0;
4509
4510        if (
4511            !$_userPaymentPlan ||
4512            in_array($_userPaymentPlan,Configure::read('counselor.not_allowed_payment_plan_id'))
4513        ) {
4514              $hideCouselorFromMember = 1;
4515        }
4516
4517        $textbookOptionArr = array();
4518        $Textbook = new TextbookController;
4519
4520        # course variable
4521        $getCourseArr = array(
4522            'teacher_id' => $teacherId,
4523            'flag' => $flag,
4524            'user_id' => $userId
4525        );
4526
4527        $course = $this->LessonText->getCourse($getCourseArr);
4528
4529            # User last viewed text book
4530            $getLastArr = array(
4531                'user_id' => $userId,
4532                'type' => 'course',
4533                'teacher_id' => $teacherId,
4534                'flag' => $flag
4535            );
4536            $courseDefault = $this->LessonText->getLastViewedBook( $getLastArr );
4537            $courseId = $courseDefault['courseId'];
4538            $curriculumId = $courseDefault['curriculumId'];
4539            $lessonTextId = $courseDefault['lessonTextId'];
4540
4541        $textbookOptionArr['courseArr'] = $course;
4542        $textbookOptionArr['courseSelected'] = isset($textbookOptionArr['courseArr'][$courseId]) ? $textbookOptionArr['courseArr'][$courseId] : 0;
4543
4544        $dataSetOption = isset($textbookOptionArr['courseArr'][$courseId]) ? $textbookOptionArr['courseArr'][$courseId] : 0;
4545        $textbookOptionArr['courseCurriculumId'] = $curriculumId;
4546        $textbookOptionArr['courseCurriculumArr'] = $dataSetOption;
4547        $courseCurriculumSelected = $textbookOptionArr['courseCurriculumArr']['Curriculum'][$curriculumId];
4548        $textbookOptionArr['courseCurriculumSelected'] = $courseCurriculumSelected['data'][$lessonTextId];
4549        $textbookOptionArr['courseCurriculumSelected']['badge'] = isset($courseDefault['textbook_info']['Curriculum']['badge']) ? $courseDefault['textbook_info']['Curriculum']['badge'] : 0;
4550        # category variable
4551        $getCategoryArr = array(
4552            'teacher_id' => $teacherId,
4553            'flag' => $flag,
4554            'user_id' => $userId
4555        );
4556        $category = $this->LessonText->getCategory($getCategoryArr);
4557
4558            # User last viewed text book
4559            $getLastArr = array(
4560                'user_id' => $userId,
4561                'type' => 'category',
4562                'teacher_id' => $teacherId,
4563                'flag' => $flag
4564            );
4565            $categoryDefault = $this->LessonText->getLastViewedBook( $getLastArr );
4566            $classId = $categoryDefault['classId'];
4567            $categoryLessonTextId = $categoryDefault['lessonTextId'];
4568
4569        $textbookOptionArr['categoryArr'] = $category;
4570        $textbookOptionArr['categorySelected'] = isset($textbookOptionArr['categoryArr'][$classId]) ? $textbookOptionArr['categoryArr'][$classId] : 0;
4571        $textbookArr = $this->LessonText->getTextBookCategory($textbookOptionArr['categorySelected']['ClassMaster']['id'],$userId, $flag);
4572        $textbookOptionArr['categoryClassArr'] = $textbookArr['data'];
4573        $textbookOptionArr['categoryClassSelected'] = isset($textbookOptionArr['categoryClassArr'][$categoryLessonTextId]) ? $textbookOptionArr['categoryClassArr'][$categoryLessonTextId] : 0;
4574
4575        # ------ default user textbook in iframe
4576        $defaultTextbookType = 2;
4577        $getLastArr = array(
4578            'user_id' => $userId,
4579            'type' => 'all',
4580            'teacher_id' => $teacherId,
4581            'flag' => $flag
4582        );
4583        $lastBookType = $this->LessonText->getLastViewedBook( $getLastArr );
4584        $defaultTextbookType = $lastBookType['textbook_type'];
4585
4586        # - since course is the first option shown
4587        if ( $defaultTextbookType ) {
4588            if ( $defaultTextbookType == 1 ) {
4589                # Course
4590                $defaulClassId = $textbookOptionArr['courseCurriculumSelected']['class_id'];
4591                $defaulChapterId = $textbookOptionArr['courseCurriculumSelected']['chapter_id'];
4592            } else {
4593                # Category
4594                $defaulClassId = isset($textbookOptionArr['categoryClassSelected']['LessonText']['class_id']) ? $textbookOptionArr['categoryClassSelected']['LessonText']['class_id'] : 0;
4595                $defaulChapterId = isset($textbookOptionArr['categoryClassSelected']['LessonText']['chapter_id']) ? $textbookOptionArr['categoryClassSelected']['LessonText']['chapter_id'] : 0;
4596            }
4597        } else {
4598            # if the user don't have lastviewed ( Category )
4599            $defaulClassId = $textbookOptionArr['categoryClassSelected']['LessonText']['class_id'];
4600            $defaulChapterId = $textbookOptionArr['categoryClassSelected']['LessonText']['chapter_id'];
4601        }
4602        //use textbook of the reserve schedule
4603        if($lessonNowReservation) {
4604            $textbookOptionArr['defaulTextbook'] = "/HtmlTextbook/index?class_id={$lessonSchedule['class_id']}&chapter_id={$lessonSchedule['chapter_id']}";
4605        } else {
4606            $textbookOptionArr['defaulTextbook'] = "/HtmlTextbook/index?class_id={$defaulClassId}&chapter_id={$defaulChapterId}";
4607        }
4608        $textbookOptionArr['textbook_type'] = $defaultTextbookType;
4609        $textbookOptionArr['hide_switch'] = false;
4610        # ---------------- iframe end
4611
4612        //set flag for hide counselor textbook
4613        $textbookOptionArr['hide_counselor_info'] = $hideCouselorFromMember;
4614
4615        $view = new View($this, false);
4616        $result['option'] = $view->element('modal_textbook_selection',array('optionArr' => $textbookOptionArr));
4617        $result['textbook_default'] = $textbookOptionArr['defaulTextbook'];
4618        $result['textbook_type'] = $textbookOptionArr['textbook_type'];
4619
4620        return json_encode($result);
4621    }
4622
4623    /**
4624     * @api {post} /user/waiting/getAllTextbookOption getAllTextbookOption()
4625     * @apiName getAllTextbookOption
4626     * @apiGroup Waiting
4627     * @apiDescription Retrieves all textbook options for the authenticated user in Native Camp. It returns various information about the available textbooks, including courses, series, and user preferences.
4628     *
4629     * @apiBody {String} [teacher_id] The ID of the teacher.
4630     * @apiBody {String} [flag=all] The environment flag (e.g., lesson_now, reservation).
4631     * @apiBody {String} [live_flag] The live flag.
4632     * @apiBody {String} [action] The action to perform (e.g., setNextTextbookChapter).
4633     * @apiBody {String} [localizeDir] The localization directory.
4634     * @apiBody {String} [connectId] The connect ID of the textbook.
4635     * @apiBody {String} [resFlag] The reservation flag.
4636     * @apiBody {String} [textbook_level] The textbook level.
4637     * @apiBody {Boolean} [favorite_textbook_only=0] Indicates if only favorite textbooks should be retrieved.
4638     * 
4639     * @apiSuccess {Object} result The result object.
4640     * @apiSuccess {String} result.option The HTML content for the textbook options.
4641     * @apiSuccess {Boolean} result.levelFiltered Indicates if the textbooks are filtered by level.
4642     * @apiSuccess {String} result.textbook_default The default textbook URL.
4643     * @apiSuccess {Number} result.textbook_type The type of the textbook (1: Course, 2: Series).
4644     * @apiSuccess {Boolean} result.reservation_flag Indicates if the textbook is for reservation.
4645     * @apiSuccess {Boolean} result.disable_button_flag Indicates if the button should be disabled.
4646     * @apiSuccess {Boolean} result.textbook_live_lesson_flg Indicates if the textbook is for live lessons.
4647     * @apiSuccess {Object} result.user_preset_textbook_data The user preset textbook data.
4648     * @apiSuccess {Number} result.user_preset_textbook_data.id The ID of the textbook category.
4649     * @apiSuccess {Number} result.user_preset_textbook_data.connect_id The connect ID of the textbook.
4650     * @apiSuccess {Number} result.user_preset_textbook_data.sub_cat_id The subcategory ID of the textbook.
4651     * @apiSuccess {Number} result.user_preset_textbook_data.textbook_id The ID of the textbook.
4652     * @apiSuccess {Boolean} result.user_preset_textbook_data.display_flag Indicates if the textbook should be displayed.
4653     * @apiSuccess {Number} result.user_preset_textbook_data.textbook_type The type of the textbook.
4654     * @apiSuccess {Boolean} result.userPresetDisplayFlg Indicates if the user preset display flag is set.
4655     *
4656     * @apiSuccessExample {json} Success-Response:
4657     *     {
4658     *         "option": "<div>Textbook Options</div>",
4659     *         "levelFiltered": false,
4660     *         "textbook_default": "/HtmlTextbook/index?connect_id=123&html_dir=dir&chapter_id=1&isFromModal=1",
4661     *         "textbook_type": 1,
4662     *         "reservation_flag": true,
4663     *         "disable_button_flag": 0,
4664     *         "textbook_live_lesson_flg": true,
4665     *         "user_preset_textbook_data": {
4666     *             "id": 1,
4667     *             "connect_id": 123,
4668     *             "sub_cat_id": 2,
4669     *             "textbook_id": 3,
4670     *             "display_flag": true,
4671     *             "textbook_type": 1
4672     *         },
4673     *         "userPresetDisplayFlg": true
4674     *     }
4675     *
4676     * @apiError {String} status The status of the request (NG).
4677     * @apiError {String} message The error message.
4678     *
4679     * @apiErrorExample {json} Error-Response:
4680     *     {
4681     *         "status": "NG",
4682     *         "message": "Invalid request."
4683     *     }
4684     * 
4685     * @apiSampleRequest off
4686     */
4687    public function getAllTextbookOption() {
4688        // increase time limit
4689        set_time_limit(60);
4690        // increase max execution time
4691        ini_set('max_execution_time', 60);
4692        // inscrease memory limit
4693        myTools::alterPHPMemoryLimit('512M');
4694        $this->autoRender = false;
4695        $result = array();
4696        $textbook_category_type = 0;
4697        $lesson_text_id = 0;
4698        //set user id
4699        $userId = $this->Auth->user('id') ?? false;
4700        $param = array('user_id' => $userId);
4701        $textbookOptionArr = array();
4702        $teacherId = isset($this->request->data['teacher_id'])? $this->request->data['teacher_id'] : null;
4703        $envFlag = isset($this->request->data['flag'])? $this->request->data['flag'] : 'all';
4704        $liveFlag = isset($this->request->data['live_flag']) ? $this->request->data['live_flag'] : null;
4705        $connectIdCourse = $connectIdSeries = null;
4706        $action = (isset($this->request->data['action']) && $this->request->data['action'] == 'setNextTextbookChapter') ? $this->request->data['action'] : null;
4707        $isCourse = false;
4708        $teacherBadgeTextbooks     = array();
4709        $counselorTeacher = 0;
4710        $studentFinishedCallanLevelCheck = ClassRegistry::init('User')->hasFinishedCallanLevelCheck(array(
4711            'user_id' => $userId,
4712            'removeRelatedData' => true
4713        ));
4714
4715        // - if has localize directory
4716        if (isset($this->request->data['localizeDir']) && mb_strlen($this->request->data['localizeDir'])) {
4717            $this->localizeDir = $this->request->data['localizeDir'];
4718        }        
4719
4720        // NJ-5836
4721        // set params
4722        $displayRestrictionParams = array(
4723            'lang' => $this->localizeDir
4724        );
4725
4726        // get display restriction setting
4727        $displayRestriction = $this->TextbookCategory->getDisplayRestrictionSettings($displayRestrictionParams);
4728        
4729        //NC-8728 check if user is valid for Study Sapuri Business English Daily textbooks
4730        $userValidForSSBEDT = $this->userValidForSSBEDT();
4731
4732        //NC-8911: check user if for global course
4733        $isUserForGlobalCourse = false;
4734        if(isset($this->localizeDir) && $this->localizeDir !== Configure::read('default.user_language')) {
4735            $isUserForGlobalCourse = true;
4736        }
4737
4738        // NJ-9489 : check if membership is allowed to display counselor information
4739        $_userPaymentPlan = $this->sharedUserData['User']['payment_plan_id'];
4740        $hideCouselorFromMember = 0;
4741
4742        if (
4743            !$_userPaymentPlan ||
4744            in_array($_userPaymentPlan,Configure::read('counselor.not_allowed_payment_plan_id'))
4745        ) {
4746          $hideCouselorFromMember = 1;
4747        }
4748
4749        // check for counselor type teacher
4750        if ( $teacherId && $envFlag == "lesson_now" ) {
4751            $this->Teacher->openDBReplica();
4752            $counselorTeacher = $this->Teacher->find('count', array(
4753                'conditions' => array(
4754                    'Teacher.id' => $teacherId,
4755                    'Teacher.counseling_flg' => 1,
4756                    'Teacher.status' => 1
4757                ),
4758                'recursive' => -1
4759            ));
4760            $this->Teacher->closeDBReplica();
4761        }
4762        // filter textbook with teacher badge for dropwdown only : display all textbooks for Textbook page
4763        if ( $teacherId && !$counselorTeacher && $envFlag != "all" ) {
4764            $teacherBadgeTextbooks = ClassRegistry::init('TeacherBadge')->getTeacherBadge(array('teacher_id' => $teacherId, 'flag' => $envFlag));
4765        }
4766
4767        // check if student has reserved entry level
4768        $lessonScheduleModel = ClassRegistry::init('LessonSchedule');
4769        $lessonScheduleModel->clear();
4770        $hasReservedCallanLevelCheck = $lessonScheduleModel->hasReservedCallanLevelCheck(array('user_id' => $userId));
4771
4772        // Default Textbook
4773        $defaultParam = array(
4774            'env_flag' => $envFlag,
4775            'reservation_flag' => isset($this->request->data['resFlag'])? $this->request->data['resFlag'] : null,
4776            'select_method' => "first",
4777            'teacher_id' => $teacherId,
4778            'user_id' => $userId,
4779            'load_description' => false,
4780            'userValidForSSBEDT' => $userValidForSSBEDT,
4781            'user_locale' => $this->localizeDir,
4782            'isUserForGlobalCourse' => $isUserForGlobalCourse,
4783            'isCouncelor' => $counselorTeacher,
4784            'joinPreTextbookId' => ( !empty($teacherBadgeTextbooks['textbookIdArray']) && count($teacherBadgeTextbooks['textbookIdArray']) > 100 ) ? true : false,
4785            'studentFinishedCallanLevelCheck' => $studentFinishedCallanLevelCheck,
4786            'studentReservedCallanLevelCheck' => $hasReservedCallanLevelCheck,
4787            'removeRelatedData' => true,
4788            'displayRestriction' => $displayRestriction,
4789            'fetch_favorite' => true
4790        );
4791
4792        if (isset($this->request->data['connectId']) && !empty($this->request->data['connectId'])) {
4793            $defaultParam['connect_id'] = $this->request->data['connectId'];
4794        }
4795
4796        // - add additional parametes for global textbook
4797        if (isset($this->localizeDir) && in_array($this->localizeDir,Configure::read("global_textbook_support_languages"))) {
4798            $defaultParam['user_locale'] = $this->localizeDir;
4799        }
4800        $defaultTextbookData = $this->Textbook->getTextbooks($defaultParam);
4801        // if default textbook category is callan and student has yet to finish callan level check
4802        if (
4803            (isset($defaultTextbookData['res_data']['TextbookCategory']['textbook_category_type']) && $defaultTextbookData['res_data']['TextbookCategory']['textbook_category_type'] == 2)
4804            && (isset($defaultTextbookData['res_data']['Textbook']['callan_level_check']) && !$defaultTextbookData['res_data']['Textbook']['callan_level_check'])
4805            && !$studentFinishedCallanLevelCheck
4806        ) {
4807            $defaultParam['tb_default_levelcheck'] = true;
4808            $defaultTextbookData = $this->Textbook->getTextbooks($defaultParam);
4809
4810        // if not callan
4811        } else {
4812            //  NC-7592 - set next textbook chapter/series within the same category
4813            if ($action !== null && $action === 'setNextTextbookChapter') {
4814                $textbookDatails = isset($defaultTextbookData['res_data']) && isset($defaultTextbookData['res_data']['Textbook']) ? $defaultTextbookData['res_data']['Textbook'] : null;
4815                $textbookConnectDetails = $defaultTextbookData['res_data']['TextbookConnect'];
4816                $allTextbookParams = array(
4817                    'category_id' => $textbookConnectDetails['category_id'],
4818                    'connect_id' => $textbookConnectDetails['id'],
4819                    'subcategory_id' => $textbookConnectDetails['subcategory_id'],
4820                    'textbook_main_topic_id' => isset($textbookDatails['main_topic_id']) && $textbookDatails['main_topic_id'] ? $textbookDatails['main_topic_id'] : null,
4821                );
4822                $allTextbookChapters = $this->TextbookConnect->getTextbookPrevAndNextFunction($allTextbookParams);
4823                // if has next textbook chapter, preset
4824                if (
4825                    is_array($allTextbookChapters) && !is_null($allTextbookChapters)
4826                    && ($allTextbookChapters['next'] !== '' && !is_null($allTextbookChapters['next']))
4827                ) {
4828                    $newPresetTextbookConnectId = $allTextbookChapters['next'];
4829                    $saveParams = array('userId' => $userId, 'connectId' => $newPresetTextbookConnectId);
4830                    $saveNextTextbookChapter = $this->saveTextbookPreset($saveParams);
4831                    // pull new default data
4832                    $defaultTextbookData = $this->Textbook->getTextbooks($defaultParam);
4833                }
4834            }
4835        }
4836        $defaultTextbook = $defaultTextbookData['res_data'];
4837        $defaultConnectId = $defaultTextbook['TextbookConnect']['id'];
4838        $defaultTextbookCategoryId = $defaultTextbook['TextbookCategory']['id'];
4839        // course
4840        if ($defaultTextbook['TextbookCategory']['type_id'] == 1) {
4841            $connectIdCourse = $defaultTextbook['TextbookConnect']['id'];
4842            $isCourse = true;
4843        }
4844        // series
4845        if ($defaultTextbook['TextbookCategory']['type_id'] == 2) {
4846            $connectIdSeries = $defaultTextbook['TextbookConnect']['id'];
4847        }
4848        // Get all Book
4849        $getAllBookArr = array(
4850            'env_flag' => $envFlag,
4851            'teacher_id' => $teacherId,
4852            'select_method' => 'all',
4853            'mode' => 'combine',
4854            'preset' => 'off',
4855            'user_id' => $userId,
4856            'load_description' => false,
4857            'userValidForSSBEDT' => $userValidForSSBEDT,
4858            'user_locale' => $this->localizeDir,
4859            'isUserForGlobalCourse' => $isUserForGlobalCourse,
4860            'is_course' => $isCourse,
4861            'isCouncelor' => $counselorTeacher,
4862            'studentFinishedCallanLevelCheck' => $studentFinishedCallanLevelCheck,
4863            'studentReservedCallanLevelCheck' => $hasReservedCallanLevelCheck,
4864            'removeRelatedData' => true,
4865            'displayRestriction' => $displayRestriction,
4866            'ranked_textbook' => ($this->isStudySapuriTosUser || $this->isStudySapuriUser) ? false : true,
4867            'fetch_favorite' => true
4868        );
4869
4870        if (isset($this->request->data['textbook_level']) && !empty($this->request->data['textbook_level'])) {
4871            $getAllBookArr['textbook_level'] = $this->request->data['textbook_level'];
4872        }
4873        
4874        // NC-7593 add favorites on textbook return
4875        if ($userId) {
4876            $params = array("user_id" => $userId);
4877            $textbookFavData = $this->UserTextbookFavorite->getUserFavoriteTextbooks($params);
4878            $getAllBookArr['textbookFavData'] = $textbookFavData;
4879        }
4880
4881        // - add additional parametes for global textbook
4882        if (isset($this->localizeDir) && in_array($this->localizeDir,Configure::read("global_textbook_support_languages"))) {
4883            $getAllBookArr['user_locale'] = $this->localizeDir;
4884        }
4885
4886        $allBookData = $this->Textbook->getTextbooks($getAllBookArr);
4887        $allBook = $allBookData['res_data'];
4888
4889        // course variable
4890        $course = $allBook['course'];
4891        $getCoursePresetArr = array(
4892            'env_flag' => 'all',
4893            'textbook_type' => 1,
4894            'select_method' => "first",
4895            'teacher_id' => $teacherId,
4896            'connect_id' => $connectIdCourse,
4897            'user_id' => $userId,
4898            'user_locale' => $this->localizeDir,
4899            'load_description' => false,
4900            'isCouncelor' => $counselorTeacher,
4901            'isForReservation' => ($envFlag == 'reservation') ? true : false,
4902            'joinPreTextbookId' => ( !empty($teacherBadgeTextbooks['textbookIdArray']) && count($teacherBadgeTextbooks['textbookIdArray']) > 100 ) ? true : false,
4903            'studentFinishedCallanLevelCheck' => $studentFinishedCallanLevelCheck,
4904            'studentReservedCallanLevelCheck' => $hasReservedCallanLevelCheck,
4905            'removeRelatedData' => true,
4906            'displayRestriction' => $displayRestriction,
4907            'fetch_favorite' => true
4908        );
4909        $coursePresetData = $this->Textbook->getTextbooks($getCoursePresetArr);
4910        $coursePreset = $coursePresetData['res_data'];
4911
4912        // User last viewed text book
4913        $courseId = $coursePreset['TextbookCategory']['id'];
4914        $courseSubCatId = $coursePreset['TextbookSubcategory']['id'];
4915        $courseSubCatBadge = isset($coursePreset['TextbookSubcategory']['badge']) && $coursePreset['TextbookSubcategory']['badge'] ? $coursePreset['TextbookSubcategory']['badge'] : null;
4916        $courseConnectId = $coursePreset['TextbookConnect']['id'];
4917        $courseLessonTextId = $coursePreset['Textbook']['id'];
4918
4919
4920        $textbookOptionArr['courseArr'] = $course;
4921        $textbookOptionArr['courseSelected'] = isset($textbookOptionArr['courseArr'][$courseId]) ? $textbookOptionArr['courseArr'][$courseId] : 0;
4922
4923        $dataSetOption = isset($textbookOptionArr['courseArr'][$courseId]) ? $textbookOptionArr['courseArr'][$courseId] : 0;
4924
4925        $textbookOptionArr['courseSubCatId'] = $courseSubCatId;
4926
4927        $textbookOptionArr['courseSubCatArr'] = $dataSetOption;
4928
4929        $courseSubCatSelected = $textbookOptionArr['courseSubCatArr']['TextbookSubcategory'][$courseSubCatId];
4930        $textbookOptionArr['courseSubCatSelected'] = $courseSubCatSelected['textbooks'][$courseConnectId];
4931        $textbookOptionArr['courseSubCatSelected']['index_position'] = isset($coursePreset['Textbook']['index_position']) && $coursePreset['Textbook']['index_position'] ? $coursePreset['Textbook']['index_position'] : null;
4932        $textbookOptionArr['courseSubCatSelected']['badge'] = $courseSubCatBadge;
4933
4934        // category variable
4935        $series = $allBook['series'];
4936        $getSeriesPresetArr = array(
4937            'env_flag' => 'all',
4938            'textbook_type' => 2,
4939            'select_method' => "first",
4940            'connect_id' => $connectIdSeries,
4941            'user_id' => $userId,
4942            'load_description' => false,
4943            'userValidForSSBEDT' => $userValidForSSBEDT,
4944            'user_locale' => $this->localizeDir,
4945            'isUserForGlobalCourse' => false,
4946            'isCouncelor' => $counselorTeacher,
4947            'isForReservation' => ($envFlag == 'reservation') ? true : false,
4948            'removeRelatedData' => true,
4949            'displayRestriction' => $displayRestriction
4950        );
4951        $seriesPresetData = $this->Textbook->getTextbooks($getSeriesPresetArr);
4952        $seriesPreset = $seriesPresetData['res_data'];
4953
4954        // User last viewed text book
4955        $seriesId = $seriesPreset['TextbookCategory']['id'];
4956        $seriesSubCatId = $seriesPreset['TextbookSubcategory']['id'];
4957        $seriesSubCatBadge = isset($seriesPreset['TextbookSubcategory']['badge']) ? $seriesPreset['TextbookSubcategory']['badge'] : null;
4958        $seriesConnectId = $seriesPreset['TextbookConnect']['id'];
4959
4960
4961        $textbookOptionArr['seriesArr'] = $series;
4962        $textbookOptionArr['seriesSpecialArr'] = $series;
4963        $textbookOptionArr['seriesSelected'] = isset($textbookOptionArr['seriesArr'][$seriesSubCatId]) ? $textbookOptionArr['seriesArr'][$seriesSubCatId] : 0;
4964
4965        $textbookOptionArr['seriesSubCatId'] = $seriesSubCatId;
4966        $textbookOptionArr['seriesSubCatSelected'] = $series[$seriesSubCatId];
4967        $textbookOptionArr['seriesTextbookArr'] = $series[$seriesSubCatId]['Textbook'];
4968        $textbookOptionArr['seriesTextbookSelected'] = $series[$seriesSubCatId]['Textbook'][$seriesConnectId];
4969        $textbookOptionArr['seriesTextbookSelected']['index_position'] = $seriesPreset['Textbook']['index_position'];
4970        $textbookOptionArr['seriesSubCatSelected']['badge'] = $seriesSubCatBadge;
4971
4972        $getSubcatParams = array(
4973            'reservation_flag' => isset($this->request->data['resFlag'])? $this->request->data['resFlag'] : null,
4974            'teacher_id' => $teacherId,
4975            'category_id' => $defaultTextbookCategoryId,
4976            'env_flag' => $envFlag,
4977            'arrange_data' => "branch",
4978            'user_id' => $userId,
4979            'user_locale' => $this->localizeDir,
4980            'userValidForSSBEDT' => true,
4981            'isCouncelor' => $counselorTeacher,
4982            'studentFinishedCallanLevelCheck' => $studentFinishedCallanLevelCheck,
4983            'studentReservedCallanLevelCheck' => $hasReservedCallanLevelCheck,
4984            'removeRelatedData' => true,
4985            'fetch_favorite' => true
4986        );
4987        $getSubCategoryArr = $this->Textbook->getTextbooks($getSubcatParams);
4988
4989        // TextbookSubcategory
4990        if ( $defaultTextbook && ( isset( $getSubCategoryArr['res_data'] ) && $getSubCategoryArr['res_data'] ) ) {
4991            $subCategoryData = $getSubCategoryArr['res_data'];
4992            $subCategoryId = $defaultTextbook['TextbookSubcategory']['id'];
4993            $mainTopicTextbookId = isset($defaultTextbook['Textbook']['id']) && $defaultTextbook['Textbook']['id'] ? $defaultTextbook['Textbook']['id'] : null ;
4994            $textbookMainTopicId = isset($defaultTextbook['Textbook']['main_topic_id']) && $defaultTextbook['Textbook']['main_topic_id'] ? $defaultTextbook['Textbook']['main_topic_id'] : null ;
4995
4996            if ( $this->localizeDir != Configure::read('default.user_language') ) {
4997                $subCategoryName  = isset( $defaultTextbook['GlobalTextbookSubcategory']['gl_name'] ) && $defaultTextbook['GlobalTextbookSubcategory']['gl_name'] ? $defaultTextbook['GlobalTextbookSubcategory']['gl_name'] : ( isset($defaultTextbook['TextbookSubcategory']['english_name']) && $defaultTextbook['TextbookSubcategory']['english_name'] ? $defaultTextbook['TextbookSubcategory']['english_name'] : $defaultTextbook['TextbookSubcategory']['name'] ) ;
4998            } else {
4999                $subCategoryName  = $defaultTextbook['TextbookSubcategory']['name'];
5000            }
5001
5002            // check for main topic overide subcategory name for daily news
5003            if ( $mainTopicTextbookId && $textbookMainTopicId ) {
5004                $langId = ClassRegistry::init('CountryCode')->getUserLanguageId($this->localizeDir);
5005                $textbookMainTopicName = ClassRegistry::init('Textbook')->getTextbookMainTopicName($mainTopicTextbookId,$langId);
5006                if ($textbookMainTopicName) { 
5007                    $subCategoryName = $textbookMainTopicName; 
5008                }
5009            }
5010
5011            $textbookOptionArr['subCategoryData'] = $subCategoryData;
5012            $textbookOptionArr['subCategoryId'] = $subCategoryId;
5013            $textbookOptionArr['subCategoryName'] = $subCategoryName;
5014
5015            if ($envFlag == 'reservation') {
5016            $textbookOptionArr['subCategoryId'] = $subCategoryId;
5017                $textbookOptionArr['selectedSubcatTeacherTotalTextbookBadge'] = (isset($subCategoryData[$subCategoryId]['TextbookSubcategory']['teacher_total_textbook_badge'])) ? $subCategoryData[$subCategoryId]['TextbookSubcategory']['teacher_total_textbook_badge'] : 0;
5018            }
5019        }
5020
5021        // check daily news category
5022        $dailyNewsCat = false;
5023        $dailyTopicsCat = false;
5024        $textbookObj = null;
5025        if ( isset($defaultTextbook['TextbookConnect']['category_id']) && $defaultTextbook['TextbookConnect']['category_id'] == Configure::read('daily_news_cat_id.series') ) {
5026            $dailyNewsCat = true;
5027            $textbookObj = $this->Textbook;
5028        }
5029        if ( isset($defaultTextbook['TextbookConnect']['category_id']) && $defaultTextbook['TextbookConnect']['category_id'] == Configure::read('daily_topics_textbook.category_id') ) {
5030            $dailyTopicsCat = true;
5031            $textbookObj = $this->Textbook;
5032        }
5033                $eikenEnable = ( $envFlag == 'lesson_now' && in_array($defaultTextbook['TextbookConnect']['category_id'], Configure::read('eiken_category_ids')));
5034        // Textbook chapters
5035
5036        // Course
5037        if ( $defaultTextbook['TextbookCategory']['type_id'] == 1 ) {
5038            $textbookChapterArr['textbooks'] = $courseSubCatSelected['textbooks'];
5039            $selectedTextbookArr = $textbookOptionArr['courseSubCatSelected'];
5040        }
5041        // Series
5042        if ( $defaultTextbook['TextbookCategory']['type_id'] == 2 ) {
5043            $textbookChapterArr['textbooks'] = $textbookOptionArr['seriesTextbookArr'];
5044            $selectedTextbookArr = $textbookOptionArr['seriesTextbookSelected'];
5045        }
5046
5047        $textbookOptionArr['dailyNewsCat'] = $dailyNewsCat;
5048        $textbookOptionArr['dailyTopicsCat'] = $dailyTopicsCat;
5049        $textbookOptionArr['textbookObj'] = $textbookObj;
5050        $textbookOptionArr['courseSubCatArr'] = $textbookChapterArr;
5051        $textbookOptionArr['courseSubCatSelected'] = $selectedTextbookArr;
5052        $textbookOptionArr['hasFinishedCallanEntry'] = $studentFinishedCallanLevelCheck;
5053        $textbookOptionArr['textbookCategoryType'] = $defaultTextbook['TextbookCategory']['textbook_category_type'];
5054        $textbookOptionArr['eikenEnable'] = $eikenEnable;
5055        $textbookOptionArr['favorite_textbook_only'] = isset($this->request->data['favorite_textbook_only']) ? $this->request->data['favorite_textbook_only'] : 0;
5056
5057        $defaultDir = $defaultTextbook['Textbook']['html_directory'];
5058        $defaultChapId = $defaultTextbook['Textbook']['chapter_id'];
5059        $defaultBagde = isset($defaultTextbook['TextbookSubcategory']['badge'])?$defaultTextbook['TextbookSubcategory']['badge']:null;
5060
5061        //use textbook of the reserve schedule
5062        $textbookOptionArr['defaulTextbook'] = "/HtmlTextbook/index?connect_id={$defaultConnectId}&html_dir={$defaultDir}&chapter_id={$defaultChapId}&isFromModal=1";
5063        $textbookOptionArr['textbook_type'] = isset($defaultTextbook['TextbookCategory']['type_id'])? $defaultTextbook['TextbookCategory']['type_id'] : 0;
5064        $textbookOptionArr['hide_switch'] = ($textbook_category_type == 2);
5065        $textbookOptionArr['teacher_badge'] = $defaultBagde;
5066        $result['disable_button_flag'] = 0;
5067        # ---------------- iframe end
5068
5069        $view = new View($this, false);
5070
5071        //NJ-2601 : NJ-24096
5072        if ($envFlag == 'reservation') {
5073            $selectedDataTextbook = ($textbookOptionArr['textbook_type'] == 1) ? $textbookOptionArr['courseSelected'] : $textbookOptionArr['seriesSubCatSelected'];
5074            $textbookLiveLessonFlg = isset($selectedDataTextbook['TextbookCategory']['live_lesson_flg']) ? $selectedDataTextbook['TextbookCategory']['live_lesson_flg'] : false;
5075            if (isset($this->request->data['connectId']) && !empty($this->request->data['connectId']) && $defaultTextbook['TextbookCategory']['display_flag']) {
5076                $result['user_preset_textbook_data']['id'] = $selectedDataTextbook['TextbookCategory']['id']; //cat id
5077                $result['user_preset_textbook_data']['connect_id'] = $selectedTextbookArr['connect_id'];
5078                $result['user_preset_textbook_data']['sub_cat_id'] = isset($selectedDataTextbook['TextbookSubcategory']['id']) ? $selectedDataTextbook['TextbookSubcategory']['id'] : 0;
5079                $result['user_preset_textbook_data']['textbook_id'] = isset($selectedDataTextbook['Textbook'][$selectedTextbookArr['connect_id']]['id']) ? $selectedDataTextbook['Textbook'][$selectedTextbookArr['connect_id']]['id'] : 0;
5080                $result['user_preset_textbook_data']['display_flag'] = isset($courseSubCatSelected['textbooks'][$selectedTextbookArr['connect_id']]['display_flag']) ? $courseSubCatSelected['textbooks'][$selectedTextbookArr['connect_id']]['display_flag'] : 0;
5081                $result['user_preset_textbook_data']['textbook_type'] = $textbookOptionArr['textbook_type'];
5082                $result['userPresetDisplayFlg'] = $textbookOptionArr['userPresetDisplayFlg'] = $defaultTextbook['TextbookCategory']['display_flag'];
5083            } else {
5084                $textbookOptionArr['textbook_type'] = 2;
5085                $textbookOptionArr['defaulTextbook'] = "/HtmlTextbook/index?connect_id={$defaultConnectId}&html_dir={$defaultDir}&chapter_id={$defaultChapId}&isFromModal=1&emptyReservationTextbook=1";
5086                $textbookOptionArr['has_reservation_connect_id'] = false;
5087                $result['disable_button_flag'] = 1;
5088            }
5089        }
5090
5091        $textbookOptionArr['all'] = ($envFlag == 'reservation') ? false : true;
5092
5093        // - check if live reservation
5094        if ( $teacherId && $liveFlag ) {
5095            $this->Teacher->openDBReplica();
5096            $liveReservation = $this->Teacher->find('count', array(
5097                'conditions' => array(
5098                    'Teacher.id' => $teacherId,
5099                    'Teacher.live_lesson_flg' => 1,
5100                    'Teacher.status' => 1
5101                ),
5102                'recursive' => -1
5103            ));
5104            $this->Teacher->closeDBReplica();
5105
5106            if ($liveReservation) {
5107                // - disabled textbooks if live_lesson_flg is OFF
5108                if (isset($textbookLiveLessonFlg) && !$textbookLiveLessonFlg) {
5109                    $result['textbook_live_lesson_flg'] = true;
5110                }
5111                $textbookOptionArr['live_reservation'] = true;
5112            }
5113        }
5114
5115
5116        // NJ-33115 prepare bookmark data of new callan textbook
5117        if ($userId) {
5118            $bookmarkSeriesData = $this->LessonBookmark->getBookmarkData($userId, Configure::read('new_callan_textbook_category_id')[0]); // series bookmark
5119            $bookmarkCourseData = $this->LessonBookmark->getBookmarkData($userId, Configure::read('new_callan_textbook_category_id')[1]); // course bookmark
5120            
5121            $bookmarkSeries = json_decode($bookmarkSeriesData, true);
5122            $bookmarkCourse = json_decode($bookmarkCourseData, true);
5123            if (isset($bookmarkSeries['bookmark_id']) && !empty($bookmarkSeries['bookmark_id'])) {
5124                $textbookOptionArr['bookmark']['series'] = $bookmarkSeries;
5125            }
5126            
5127            if (isset($bookmarkCourse['bookmark_id']) && !empty($bookmarkCourse['bookmark_id'])) {
5128                $textbookOptionArr['bookmark']['course'] = $bookmarkCourse;
5129            }
5130        }
5131
5132        //set flag for hide counselor textbook
5133        $textbookOptionArr['hide_counselor_info'] = $hideCouselorFromMember;
5134        $textbookOptionArr['favorites'] = isset($allBook['favorites']) ? $allBook['favorites'] : false;
5135        $textbookOptionArr['liveFlag'] = $liveFlag;
5136
5137        if (isset($this->request->data['textbook_level']) && !empty($this->request->data['textbook_level'])) {
5138            $textbookOptionArr['textbook_level'] = $this->request->data['textbook_level'];
5139            $result['option'] = $view->element('textbook_category_selection',array(
5140                'courseArr' => isset($textbookOptionArr['courseArr']) ? $textbookOptionArr['courseArr'] : false,
5141                'seriesArr' => isset($textbookOptionArr['seriesArr']) ? $textbookOptionArr['seriesArr'] : false,
5142                'favorites' => isset($textbookOptionArr['favorites']) ? $textbookOptionArr['favorites'] : false,
5143                'liveFlag' => $liveFlag
5144            ));
5145            $result['levelFiltered'] = true;
5146        } else {
5147            $result['option'] = $view->element('modal_textbook_selection_2',array('optionArr' => $textbookOptionArr));
5148            $result['levelFiltered'] = false;
5149        }
5150        
5151        // - set result
5152        $result['textbook_default'] = $textbookOptionArr['defaulTextbook'];
5153        $result['textbook_type'] = $textbookOptionArr['textbook_type'];
5154        $result['reservation_flag'] = $defaultTextbook['TextbookCategory']['reservation_flg'];
5155        
5156        // - return json encoded data
5157        $this->response->type('json');
5158        $this->response->body(json_encode($result));
5159        return $this->response;
5160    }
5161
5162    /**
5163     * @api {post} /user/waiting/saveTexbook saveTextbookPreset()
5164     * @apiName saveTextbookPreset
5165     * @apiGroup Waiting
5166     * @apiDescription Saves the preset textbook for the authenticated user in Native Camp. It returns the status of the save operation and the details of the preset textbook.
5167     *
5168     * @apiBody {String} userId The ID of the user.
5169     * @apiBody {Object} presetParams The preset parameters.
5170     * @apiBody {Boolean} [is_pc_flg=true] Indicates if the request is from a PC.
5171     * @apiBody {String} [lang] The language code.
5172     * @apiBody {Boolean} [bypass_dummy_textbook_checker=true] Indicates if the dummy textbook checker should be bypassed.
5173     * 
5174     * @apiSuccess {Boolean} result Indicates whether the preset textbook was successfully saved.
5175     * @apiSuccess {String} image The image URL of the preset textbook.
5176     * @apiSuccess {String} name The name of the preset textbook.
5177     * @apiSuccess {String} cat_name The category name of the preset textbook.
5178     * @apiSuccess {String} chapter The chapter of the preset textbook.
5179     * @apiSuccess {Number} textbookCategoryTypeId The category type ID of the preset textbook.
5180     *
5181     * @apiSuccessExample {json} Success-Response:
5182     *     {
5183     *         "result": true,
5184     *         "image": "http://example.com/image.jpg",
5185     *         "name": "Textbook Name",
5186     *         "cat_name": "Category Name",
5187     *         "chapter": "Chapter 1",
5188     *         "textbookCategoryTypeId": 1
5189     *     }
5190     *
5191     * @apiError {String} status The status of the request (NG).
5192     * @apiError {String} message The error message.
5193     *
5194     * @apiErrorExample {json} Error-Response:
5195     *     {
5196     *         "status": "NG",
5197     *         "message": "Invalid request."
5198     *     }
5199     * 
5200     * @apiSampleRequest off
5201     */
5202    public function saveTextbookPreset($params = array()) {
5203        $status = false;
5204        $reservation_flg = 0;
5205        $this->autoRender = false;
5206
5207        // set preset params
5208        $presetParams = array(
5209            'is_pc_flg' => true,
5210            'lang' => $this->localizeDir,
5211            'bypass_dummy_textbook_checker'    => true
5212        );
5213
5214        if ($this->request->is('ajax')) {
5215            $data = $this->request->data;
5216
5217            // NJ-5836 set additional preset params
5218            $data['presetParams'] = $presetParams;
5219
5220            //if save succesful get the reservation flg of the textbook
5221            if ($this->UsersLastViewedTextbook->savePresetTextbook($data)) {
5222                $status = true;
5223            }
5224
5225            // 8020
5226            $presetParams = array("user_id" => $data['userId']);
5227
5228            //add additional parameter in fetching preset textbook
5229            if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))) {
5230                $presetParams["lang"] = $this->localizeDir;
5231            }
5232
5233            // check if user is valid for Study Sapuri Business English Daily textbooks
5234            if ((isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')) &&
5235                ($this->Auth->loggedIn() && $this->Auth->user('currency_code') == Configure::read('default.user_currency'))
5236              ){
5237                $presetParams['userValidForSSBEDT'] = true;
5238            }
5239
5240            //fetch preset
5241            $textbookConnectId = $this->UsersLastViewedTextbook->getPresetTextbook($presetParams);
5242
5243        // request is POST
5244        } else {
5245            $data = $params;
5246
5247            // NJ-5836 set additional preset params
5248            $data['presetParams'] = $presetParams;
5249
5250            //if save succesful get the reservation flg of the textbook
5251            if ($this->UsersLastViewedTextbook->savePresetTextbook($data)) {
5252                $status = true;
5253            }
5254
5255            // 8020
5256            $presetParams = array("user_id" => $data['userId']);
5257
5258            //add additional parameter in fetching preset textbook
5259            if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))) {
5260                $presetParams["lang"] = $this->localizeDir;
5261            }
5262
5263            // check if user is valid for Study Sapuri Business English Daily textbooks
5264            if (
5265                (isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')) &&
5266                ($this->Auth->loggedIn() && $this->Auth->user('currency_code') == Configure::read('default.user_currency'))
5267            ){
5268                $presetParams['userValidForSSBEDT'] = true;
5269            }
5270
5271            //fetch preset
5272            $textbookConnectId = $this->UsersLastViewedTextbook->getPresetTextbook($presetParams);
5273        }
5274        echo json_encode(array(
5275                'result' => $status,
5276                'image' => $textbookConnectId['image'],
5277                'name' => $textbookConnectId['name'],
5278                'cat_name' => $textbookConnectId['cat_name'],
5279                'chapter' => $textbookConnectId['chapter'],
5280                'textbookCategoryTypeId' => $textbookConnectId['textbook_info']['TextbookCategory']['type_id']
5281        ));
5282        exit;
5283    }
5284
5285    /**
5286     * @api {get} /user/:language/waiting/callLessonAlertandStartButton callLessonAlertandStartButton()
5287     * @apiName callLessonAlertandStartButton
5288     * @apiGroup Waiting
5289     * @apiDescription Retrieves the lesson alert and start button information for the authenticated user in Native Camp. It returns various information about the lesson status, user eligibility, and more.
5290     *
5291     * @apiParam {String} language The language code for the page.
5292     * 
5293     * @apiBody {String} studentId The ID of the student.
5294     * @apiBody {String} teacherId The ID of the teacher.
5295     * @apiBody {Boolean} counselingFlg Indicates if the lesson is a counseling session.
5296     * @apiBody {Boolean} [emergencyFlg=false] Indicates if the lesson is an emergency lesson.
5297     * @apiBody {Boolean} [isSpViewer=false] Indicates if the viewer is using a special viewer.
5298     * @apiBody {Boolean} [redLamp=false] Indicates if the red lamp is on.
5299     * 
5300     * @apiSuccess {Object} result The result object.
5301     * @apiSuccess {String} result.lesson_alert The HTML content for the lesson alert.
5302     * @apiSuccess {String} result.lesson_start_button The HTML content for the lesson start button.
5303     * @apiSuccess {Number} result.isReserved Indicates if the lesson is reserved (1: Yes, 0: No).
5304     * @apiSuccess {Number} result.unverifiedSMS Indicates if the SMS verification is unverified (1: Yes, 0: No).
5305     * @apiSuccess {Number} result.lessonStartIsNormalLitePLan Indicates if the user is on a normal lite plan (1: Yes, 0: No).
5306     * @apiSuccess {Number} result.studentDelayInSeconds The delay in seconds for the student lesson priority.
5307     *
5308     * @apiSuccessExample {json} Success-Response:
5309     *     {
5310     *         "lesson_alert": "<div>Lesson Alert Content</div>",
5311     *         "lesson_start_button": "<button>Start Lesson</button>",
5312     *         "isReserved": 1,
5313     *         "unverifiedSMS": 0,
5314     *         "lessonStartIsNormalLitePLan": 1,
5315     *         "studentDelayInSeconds": 3000
5316     *     }
5317     *
5318     * @apiError {String} status The status of the request (NG).
5319     * @apiError {String} message The error message.
5320     *
5321     * @apiErrorExample {json} Error-Response:
5322     *     {
5323     *         "status": "NG",
5324     *         "message": "Invalid request."
5325     *     }
5326     * 
5327     * @apiSampleRequest off
5328     */
5329    public function callLessonAlertandStartButton() {
5330        $this->autoRender = false;
5331        $view = new View($this, false);
5332        $get = $this->request->query;
5333        $lessonType = false;
5334        $displayFamilyAlert = false;
5335        $isSpViewer = !empty($get['isSpViewer']) ? 1: 0;
5336        $showTakeBusinessTestModal = false;
5337
5338        // check if teacher and student id exists
5339        if (
5340            !isset($get['studentId']) &&
5341            !isset($get['teacherId']) &&
5342            !isset($get['counselingFlg'])
5343        ) {
5344            throw new Exception("Invalid parameters!");
5345        }
5346
5347        // set vars
5348        $device = false;
5349        $ua = (!empty(myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']))) ? myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']) : '';
5350        $studentId = $get['studentId'];
5351        $teacherId = $get['teacherId'];
5352        $counselingFlg = $get['counselingFlg'];
5353        $isEmergencyLesson = (isset($get['emergencyFlg']) && $get['emergencyFlg']) ? true : false;
5354        $isGuestViwer = empty($studentId) ? 1 : 0;
5355        $isMobileView = $this->RequestHandler->isMobile();
5356
5357        $isRedLamp = isset($get['redLamp']) && $get['redLamp'] == "1" ? true : false;
5358        // get the data
5359        $teacherData = $this->Teacher->find('first', array(
5360            'fields' => array(
5361                'Teacher.home_flg',
5362                'Teacher.avatar_flg',
5363                'Teacher.avatar_parent_flg',
5364                'Teacher.avatar_id',
5365                'Teacher.native_speaker_flg',
5366            ),
5367            'conditions' => array(
5368                'Teacher.id' => $teacherId
5369            ),
5370            'recursive' => -1
5371        ));
5372
5373        // NJ-48797
5374        $isAvatarTeacher = isset($teacherData['Teacher']['avatar_flg']) && $teacherData['Teacher']['avatar_flg'] == 1;
5375
5376        if ($isAvatarTeacher) {
5377            $avatarParentFlg = isset($teacherData['Teacher']['avatar_parent_flg']) && $teacherData['Teacher']['avatar_parent_flg'] == 1;
5378        
5379            if (!$avatarParentFlg) {
5380                $getParentAvatarTeacher = $this->Teacher->find('first', array(
5381                    'fields' => array('Teacher.id', 'Teacher.native_speaker_flg'),
5382                    'conditions' => array(
5383                        'Teacher.id' => $teacherData['Teacher']['avatar_id'],
5384                        'Teacher.avatar_parent_flg' => 1
5385                    ),
5386                    'recursive' => -1
5387                ));
5388            } else {
5389                $getParentAvatarTeacher = $teacherData;
5390            }
5391        }
5392
5393        $param = array(
5394            'homeFlag' => isset($teacherData['Teacher']['home_flg']) ? $teacherData['Teacher']['home_flg'] : null,
5395            'isGuestViwer' => $isGuestViwer
5396        );
5397
5398        $canLesson = LessonOnairTable::canLesson($teacherId, $studentId, $param);
5399
5400        $liveData = isset($canLesson['liveLessonDetail']) && !empty($canLesson['liveLessonDetail']) ? $canLesson['liveLessonDetail'] : [];
5401        $hasRemainingLife = false;
5402
5403        if (
5404            $liveData &&
5405            $liveData['lesson_started'] &&
5406            !$liveData['lesson_finish'] &&
5407            !$isSpViewer &&
5408            !$isGuestViwer &&
5409            !$isMobileView
5410        ) {
5411
5412            // if api token is not set
5413            if (empty($this->sharedUserData['User']['api_token'])) {
5414
5415                $userApiToken = $this->User->generateAndSaveApiToken($studentId);
5416
5417                // update auth value
5418                $this->Session->write('Auth.User.api_token', $userApiToken);
5419            }
5420
5421            // open tunnel
5422            myTools::initializeApiTunnel(array('ChivoxTrainingController'));
5423
5424            // initialize controller
5425            $ctc = new ChivoxTrainingController();
5426
5427            // set data
5428            $ctc->params = [
5429                'nc_terminal_type' => 1, // pc
5430                'users_api_token' => $this->Auth->user('api_token'),
5431                'is_live_lesson' => 1,
5432                'chat_hash' => isset($liveData['chat_hash']) ? $liveData['chat_hash'] : null
5433            ];
5434
5435            // get remaining life details
5436            $noRemainingLifeDetails = json_decode($ctc->trainings_life_status(), true);
5437
5438            if (isset($noRemainingLifeDetails['error'])) {
5439                throw new Exception($noRemainingLifeDetails['error']['message']);
5440            }
5441
5442            $hasRemainingLife = ($noRemainingLifeDetails['infinite_life_flg'] || $noRemainingLifeDetails['remaining_life'] > 0 || $liveData['lesson_joined']) ? true : false;
5443        }
5444
5445        // check user agent
5446        if (strpos($ua, 'Silk') !== false) {
5447            $device = 'kindle';
5448        } else if (strpos($ua, 'Android') !== false) {
5449            $device = 'andriod';
5450        } else if (strpos($ua, 'iPhone') !== false) {
5451            $device = 'ios';
5452        } else if (strpos($ua, 'iPad') !== false) {
5453            $device = 'ios';
5454        } else if (strpos($ua, 'iPod') !== false) {
5455            $device = 'ios';
5456        } else {
5457            $device = 'pc';
5458        }
5459
5460        //check browser
5461        $unsupportedBorwser = false;
5462        $browser =  $this->request->header('User-Agent');
5463        if (preg_match('/(Edg|Edge)/i',$browser) ) {
5464            $unsupportedBorwser = false;
5465        } elseif (preg_match('/(OPR)/i',$browser)) {
5466            $unsupportedBorwser = true;
5467        } elseif (preg_match('/(Chrome|Firefox|Safari)/i',$browser)) {
5468            $unsupportedBorwser = false;
5469        } else if ( 
5470            $isSpViewer
5471            && preg_match('/(iPhone|iPad|iPod|Mozilla)/i',$browser)
5472            && preg_match('/(CriOS|FxiOS)/i',$browser)
5473        ) {
5474            //-- IOS CHROME
5475            $unsupportedBorwser = false;
5476        } else {
5477            $unsupportedBorwser = true;
5478        }
5479
5480        // get the teacher's current status
5481        $queryCondition = array(
5482            'fields' => array(
5483                    'TeacherRankCoin.coins',
5484                    'LessonOnair.id',
5485                    'LessonOnair.teacher_id',
5486                    'LessonOnair.user_id',
5487                    'LessonOnair.lesson_type',
5488                    'LessonOnair.live_lesson_flg'
5489                ),
5490            'joins' => array(
5491                array(
5492                    'type' => 'LEFT',
5493                    'table' => 'teacher_rank_coins',
5494                    'alias' => 'TeacherRankCoin',
5495                    'conditions' => array('Teacher.rank_coin_id = TeacherRankCoin.id AND TeacherRankCoin.status')
5496                )
5497            ),
5498            'conditions' => array(
5499                array('Teacher.id' => $teacherId)
5500            ),
5501            'show' => 'first'
5502        );
5503        $this->Teacher->unbindModel(array('hasOne' => array('LessonOnair')));
5504
5505        if ($isEmergencyLesson && $this->isStudySapuriTosUser) {
5506            $nextEmergencySlot = $this->LessonSchedule->getEmergencyTimeSlot();
5507            $nextReserveSlot = $this->LessonSchedule->getNextReservationTimeSlot();
5508            $queryCondition['fields'][] = "(
5509                ((select smb.id from shift_work_meal_breaks as smb where smb.lesson_time >= '{$nextReserveSlot['start']}' and smb.lesson_time <= '{$nextReserveSlot['end']}' and smb.teacher_id = Teacher.id limit 1) IS NULL) AND 
5510                ((Select rs.id from lesson_schedules as rs where rs.lesson_time >= '{$nextEmergencySlot['start']}' and rs.lesson_time <= '{$nextEmergencySlot['end']}' and rs.status = 1 and rs.teacher_id = Teacher.id limit 1) IS NULL)
5511                ) as can_emergency_lesson";
5512            $queryCondition['fields'][] = "((Select rs.id from lesson_schedules as rs where rs.lesson_time >= '{$nextReserveSlot['start']}' and rs.lesson_time <= '{$nextReserveSlot['end']}' and rs.status = 1 and rs.user_id = {$studentId} limit 1) IS NULL) 
5513                as student_no_next_reservation";
5514        }
5515
5516        $commonTeacherStatusParams = array(
5517            'page_display' => 'listTeacher',
5518            'query_conditions' => $queryCondition
5519        );
5520        $lessonOnair = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
5521
5522        $teacherStatusStandByDurationFieldStr = '(CASE when TeacherStatus.status = 2 then (TIME_TO_SEC(TIMEDIFF(NOW(), TeacherStatus.created))) else 0 end) as teacher_status_standby_duration';
5523        // teacher_status if login or break
5524        $teacherStatus1 = $this->TeacherStatus->find('first', array(
5525            'fields' => array(
5526                'TeacherStatus.status',
5527                'TeacherStatus.remarks1',
5528                'TeacherStatus.remarks2',
5529                $teacherStatusStandByDurationFieldStr
5530            ),
5531            'conditions' => array('TeacherStatus.teacher_id' => $teacherId)
5532        ));
5533        
5534        $isNotAvatar = isset($lessonOnair['Teacher']['avatar_flg']) && $lessonOnair['Teacher']['avatar_flg'] == 1 ? 0 : 1; // set to FALSE/0 if teacher is avatar
5535         $isNotCounselor = isset($lessonOnair['Teacher']['counseling_flg']) && $lessonOnair['Teacher']['counseling_flg'] == 1 ? 0 : 1; // set to FALSE/0 if teacher is avatar
5536
5537        $studentRemainingSecondsDelay = 0;
5538        if( $isNotAvatar && $isNotCounselor ) {
5539            if( isset($teacherStatus1[0]['teacher_status_standby_duration']) && $teacherStatus1[0]['teacher_status_standby_duration'] ) {
5540                if( (int)$teacherStatus1[0]['teacher_status_standby_duration'] <= (int)$this->studentLessonPriorityTimeDelayInSeconds ) {
5541                    $studentRemainingSecondsDelay = (int)$this->studentLessonPriorityTimeDelayInSeconds - (int)$teacherStatus1[0]['teacher_status_standby_duration'];
5542                }
5543            }
5544        }
5545
5546        // check if lessonOnair is empty
5547        if (isset($lessonOnair['LessonOnair'])) {
5548            $tmp = (object) $lessonOnair['LessonOnair'];
5549            if (!$tmp->id) {
5550                $lessonOnair['LessonOnair'] = null;
5551            }
5552        }
5553
5554        // pass onairs data
5555        $onair = $lessonOnair['LessonOnair'];
5556
5557        // check if lessonOnair contains empty values
5558        if (!empty($onair)) {
5559            $oOnair = new LessonOnairTable($onair);
5560        }
5561
5562        // set onair
5563        if (!empty($teacherStatus1) && empty($onair)) {
5564            $oOnair = new TeacherStatusTable($teacherStatus1['TeacherStatus']);
5565        }
5566
5567        // if teacher status is '4', disable lesson
5568        if (
5569            isset($teacherStatus1['TeacherStatus']['status']) &&
5570            isset($canLesson['lessonAvailable']) &&
5571            $teacherStatus1['TeacherStatus']['status'] == 4
5572        ) {
5573            $canLesson['lessonAvailable'] = 0;
5574        }
5575
5576        // normal
5577        $resEndTime1 = 25;
5578        $resEndTime2 = 55;
5579        if ( isset($lessonOnair['Teacher']['avatar_flg']) && $lessonOnair['Teacher']['avatar_flg'] == 1 ) {
5580            $resEndTime1 = 19;
5581            $resEndTime2 = 49;
5582            // check if has upcoming reservation
5583            if (
5584                isset($canLesson['nextReservation']) &&
5585                $canLesson['nextReservation'] &&
5586                ((date("i") <= 29 && date("i") >= $resEndTime1) || (date("i") <= 59 && date("i") >= $resEndTime2)) &&
5587                isset($oOnair->status) &&
5588                isset($oOnair->connect_flg) &&
5589                $oOnair->connect_flg = 1
5590            ) {
5591                $canLesson['lessonAvailable'] = 0;
5592            }
5593
5594        }
5595
5596        // check if has upcoming reservation
5597        if (
5598            isset($canLesson['nextReservation']) &&
5599            $canLesson['nextReservation'] &&
5600            ((date("i") <= 29 && date("i") >= $resEndTime1) || (date("i") <= 59 && date("i") >= $resEndTime2)) &&
5601            isset($oOnair->status) &&
5602            isset($oOnair->connect_flg) &&
5603            $oOnair->connect_flg = 1
5604        ) {
5605            $oOnair->status = 2;
5606        }
5607
5608        //get preset textbook or last viewed
5609        $presetParams = array("user_id" => $get['studentId'], 'userValidForSSBEDT' => $this->userValidForSSBEDT());
5610
5611        //add additional parameter in fetching preset textbook
5612        if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))) {
5613            $presetParams["lang"] = $this->localizeDir;
5614        }
5615
5616        $preset_data = $this->UsersTextbookInfo->getPreset($presetParams);
5617        if(isset($preset_data['preset_connect_id']) && !empty($preset_data['preset_connect_id'])) {
5618            # for preset
5619            $presetParams['connect_id'] = $preset_data['preset_connect_id'];
5620            $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
5621
5622        } else if(isset($preset_data['last_viewed_connect_id']) && !empty($preset_data['last_viewed_connect_id'])) {
5623            # use last viewed textbook if no preset data.
5624            $presetParams['connect_id'] = $preset_data['last_viewed_connect_id'];
5625            $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
5626        }
5627
5628        // - NJ-3878 : add trapping for pc and app(api) 1 = pc 0 = app
5629        $presetParams['is_pc_flg'] = 1;
5630
5631        # fetch preset
5632        $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
5633        if(!$preset) {
5634            unset($presetParams['connect_id']);
5635            unset($presetParams['last_opened_date']);
5636            $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
5637        }
5638
5639        $lessonData = $preset["textbook_info"];
5640        $categoryId = $lessonData["TextbookCategory"]["id"];
5641        $categoryTypeId = $lessonData["TextbookCategory"]["type_id"];
5642        $textbookId = $lessonData["Textbook"]["id"];
5643        if( $categoryTypeId == 1 ) { // course
5644            $seriesId = $this->Textbook->getTextbookSeriesId(array( 'textbook_id' => $textbookId ));
5645        } else { // series
5646            $seriesId = $categoryId;
5647        }
5648
5649        // check teacher badge
5650        $checkBadge = $this->TeacherBadge->find("first", array(
5651                "conditions" => array(
5652                    "TeacherBadge.teacher_id" => $get['teacherId'],
5653                    "TeacherBadge.textbook_category_id" => $seriesId
5654                ),
5655                "fields" => array("TeacherBadge.id"),
5656                "recursive" => -1
5657            )
5658        );
5659
5660        $canLessonTextbook = false;
5661        if( $checkBadge || $counselingFlg) {
5662            $canLessonTextbook = true;
5663        }
5664
5665        //check if the preset textbook is doesn't have reserve_flg
5666        $textbookForReservationOnly = isset($preset['reservation_flg']) && !$counselingFlg ? $preset['reservation_flg'] : 0;
5667
5668        //get the textbook course / category
5669        $textbookCategoryName = isset($preset['name']) ? $preset['name'] : '' ;
5670
5671        //get next available schedule
5672        $lesson_time_stamp = floor(time() / (30 * 60)) * (30 * 60);
5673        if(isset($canLesson['nextReserve'])) {
5674            $nextSchedule = isset($canLesson['nextReserve']['start']) ? $canLesson['nextReserve']['start'] : null;
5675            $checkNextSchedule = $nextSchedule ? $this->ShiftWorkOn->checkDataExist($teacherId , $nextSchedule) : null;
5676            $checkScheduleCurrent = $this->ShiftWorkOn->checkDataExist( $teacherId , date('Y-m-d H:i:s',$lesson_time_stamp));
5677        }
5678
5679        //lesson type in lesson onair is reserved or there is a current reservation
5680        $this->LessonSchedule->recursive = 0;
5681        $reservedLessonData = $this->LessonSchedule->getReservationLessonNow($studentId);
5682        $isReserved = ((isset($lessonOnair['LessonOnair']['lesson_type']) && $lessonOnair['LessonOnair']['lesson_type'] == 2)
5683                                        || $reservedLessonData && ($reservedLessonData['Teacher']['id'] == $teacherId)) ? true : false;
5684        $corporateIndividualUser = false;
5685        $lessonOrangeButtonRemaining = false;
5686        $showNativeSpeakerWarning = false;
5687        if ($this->Auth->User('id')) {
5688            $userOnairData = $this->LessonOnair->find('first', array(
5689                'conditions' => array(
5690                    'LessonOnair.user_id' => $this->Auth->User('id'),
5691                    'LessonOnair.status' => Configure::read("lesson.status.lesson")
5692                )
5693            ));
5694
5695            $userDuplicateLesson = false;
5696            $lessonOnOther = false;
5697            $userNotEligible = false;
5698            $uOnair = isset($userOnairData['LessonOnair']) ? $userOnairData['LessonOnair']: '';
5699
5700            if ($uOnair != null) {
5701                $uOOnair = new LessonOnairTable($uOnair);
5702                //check user duplicate lesson
5703                if ($uOOnair && $uOOnair->status == 3 && $uOOnair->user_id == $this->Auth->User('id') && $uOOnair->teacher_id != $teacherId) {
5704                    $userDuplicateLesson = true;
5705                    $lessonType = $uOOnair->lesson_type;
5706                }
5707                //check lesson on others
5708                if ($oOnair && $oOnair->status == 3 && $oOnair->teacher_id == $teacherId && $oOnair->user_id != $studentId) {
5709                    $lessonOnOther = true;
5710                }
5711            }
5712
5713            //NC-6310 check user have reservation
5714            $nextReservation = LessonScheduleTable::getReservation(array(
5715                'LessonSchedule.teacher_id' => $teacherId,
5716                'LessonSchedule.user_id' =>  $this->sharedUserData['User']['id']
5717            ));
5718
5719            //check user if free or failed
5720            $user = $this->sharedUserData;
5721            $userTable = new UserTable($user['User']);
5722            $userAdminFlag = isset($user['User']['admin_flg']) ? $user['User']['admin_flg'] : '';
5723            $userFailFlag = isset($user['User']['fail_flg']) ? $user['User']['fail_flg'] : '';
5724            $userDoubleCheckFlag = isset($user['User']['double_check_flg']) ? $user['User']['double_check_flg']: '';
5725            $userCardCompany = isset($user['User']['card_company']) ? $user['User']['card_company']: '';
5726            $corporateUserFlg = isset($user['User']['corporate_id']) ? $user['User']['corporate_id'] : false;
5727
5728            // if corporate user
5729            if (isset($user['User']['corporate_id'])) {
5730                $corporateAdminPaymentMethod = $this->Corporate->getPaymentMethod($user['User']['corporate_id']);
5731                $corporateIndividualUser = $corporateAdminPaymentMethod == 1 ? true : false;
5732
5733                // NJ-3660: if 20th day onwards of the month, check if corporate user must take business test
5734                $corporateUserDate = time();
5735                $twentyPlusDayOfTheMonth = strtotime(date('Y-m-20'));
5736                $isTakenBusinessTestFlg = (isset($user['User']['monthly_speaking_business_attended_flg'])) ? $user['User']['monthly_speaking_business_attended_flg'] : 0;
5737                $isMustTakeBusinessTestFlg = (isset($user['User']['monthly_speaking_business_attended_must_flg'])) ? $user['User']['monthly_speaking_business_attended_must_flg'] : 0;
5738
5739                // if user has not yet taken the monthly test and must flag is 1
5740                // and not a reserved lesson and current date is 20+ of the month
5741                $showTakeBusinessTestModal = false;
5742                if (
5743                    ($isTakenBusinessTestFlg == 0 && $isMustTakeBusinessTestFlg == 1) &&
5744                    !$isReserved &&
5745                    (
5746                        $corporateUserDate >= $twentyPlusDayOfTheMonth ||
5747                        (
5748                            $userAdminFlag == 1 ||
5749                            (
5750                                isset($user["User"]["nickname"]) &&
5751                                strpos(strtoupper($user["User"]["nickname"]), '%%%TEST%%%') !== false
5752                            )
5753                        )
5754                    )
5755                ) {
5756                    $showTakeBusinessTestModal = true;
5757                }
5758            }
5759
5760            // NC-5409 : Corporate Limited Plan
5761            $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($user['User']['payment_plan_id']);
5762            if ( isset($corporateType) &&  $corporateType == Configure::read('corporate_type.limited') ) {
5763
5764                // check if legible
5765                if (( ($corporateType == Configure::read('corporate_type.limited') && !$isReserved) || (!$isReserved && (!$canLessonTextbook || $textbookForReservationOnly)) ||
5766                        $userDuplicateLesson || $unsupportedBorwser ||
5767                        $lessonOnOther
5768                ) && $studentId) {
5769                    $userNotEligible = true;
5770                }
5771
5772            } elseif ( isset($corporateType) &&  $corporateType == Configure::read('corporate_type.light') ) {
5773
5774                $corpLightCondition1 = (
5775                    ($corporateType == Configure::read('corporate_type.light') && !$isReserved) ||
5776                    (!$isReserved && (!$canLessonTextbook || $textbookForReservationOnly)) ||
5777                    $userDuplicateLesson ||
5778                    $unsupportedBorwser ||
5779                    $lessonOnOther
5780                );
5781                // check if legible
5782                if ( $corpLightCondition1 && $studentId) {
5783                    $userNotEligible = true;
5784                }
5785            } elseif (
5786                (
5787                    isset($lessonOnair['Teacher']['native_speaker_flg']) &&
5788                    $lessonOnair['Teacher']['native_speaker_flg']
5789                ) &&
5790                (
5791                    $user['User']['native_option'] == null ||
5792                    $user['User']['native_option'] == 0
5793                ) &&
5794                !$isReserved &&
5795                !$tmp->live_lesson_flg &&
5796                !$this->isStudySapuriTosUser
5797            ) {
5798                $userNotEligible = true;
5799                $showNativeSpeakerWarning = true;
5800            } elseif ( // NJ-48797
5801                (isset($getParentAvatarTeacher['Teacher']['native_speaker_flg']) && $getParentAvatarTeacher['Teacher']['native_speaker_flg']) &&
5802                ($user['User']['native_option'] == null || $user['User']['native_option'] == 0) && 
5803                !$isReserved &&
5804                !$tmp->live_lesson_flg &&
5805                !$this->isStudySapuriTosUser
5806            ) {
5807                $showNativeSpeakerWarning = true;
5808                $userNotEligible = true;
5809            } else {
5810                // check if legible
5811                if (((!$isReserved && (!$canLessonTextbook || $textbookForReservationOnly)) ||
5812                        $userDuplicateLesson || $unsupportedBorwser || (!$userAdminFlag && ($userFailFlag == 1 || $userDoubleCheckFlag == 2)) ||
5813                        $lessonOnOther
5814                ) && $studentId) {
5815                    $userNotEligible = true;
5816                }
5817            }
5818            
5819            // show orange button
5820            $lessonOrangeButtonRemaining = $this->triggerOrangeButton($this->Auth->User('id'), $teacherId, $userNotEligible, $unsupportedBorwser, $canLesson['lessonAvailable']);
5821
5822            # - [NJ-18003] conditions for terminate reserved lesson for sudden lesson
5823            $isReservedCanSuddenLesson = false;
5824            $isReservedCanLessonViewing = false;
5825            if (
5826                $canLessonTextbook &&             # - can lesson with the textbook
5827                !$textbookForReservationOnly && # - textbook not for reserve only
5828                !$unsupportedBorwser &&         # - supported browser
5829                $userDuplicateLesson &&         # - has lesson with other teacher
5830                $lessonType == Configure::read('lesson.type.reservation') &&
5831                !$this->isStudySapuriTosUser &&    # - not sapuri TOS user
5832                !$this->isStudySapuriUser &&    # - not sapuri user
5833                ($uOnair && $uOnair['leave_lesson']) && # - already left the reserved lesson
5834                !in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')]) && 
5835                !in_array($user['User']['payment_plan_id'], Configure::read('payment_plan_lightplan'))  # - not lite plan user
5836            ) {
5837                $isReservedCanSuddenLesson = true;
5838            }
5839
5840            if (
5841                !$this->isStudySapuriUser &&
5842                $lessonType == Configure::read('lesson.type.reservation') &&
5843                ($uOnair && $uOnair['leave_lesson']) # - already left the reserved lesson
5844            ) {
5845                $isReservedCanLessonViewing = true;
5846            }
5847            
5848            $canMidwayLesson = false;
5849            if (
5850                $canLessonTextbook &&             # - can lesson with the textbook
5851                !$textbookForReservationOnly && # - textbook not for reserve only
5852                !$unsupportedBorwser &&         # - supported browser
5853                $userDuplicateLesson &&         # - has lesson with other teacher
5854                !$this->isStudySapuriTosUser &&    # - not sapuri TOS user
5855                !in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')]) && 
5856                !in_array($user['User']['payment_plan_id'], Configure::read('payment_plan_lightplan'))  # - not lite plan user
5857            ) {
5858                $canMidwayLesson = true;
5859            }
5860        }
5861
5862        // NC-3755
5863        if (
5864            isset($this->sharedUserData['User']['parent_id']) &&
5865            !is_null($this->sharedUserData['User']['parent_id'])
5866        ) {
5867            $parent = $this->User->find('first', array(
5868                'fields' => array(
5869                    'User.id',
5870                    'User.hash16',
5871                    'User.charge_flg'
5872                ),
5873                'conditions' => array(
5874                    'User.id' => $this->sharedUserData['User']['parent_id']
5875                ),
5876                'recursive' => -1
5877            ));
5878
5879            if ($parent && $parent['User']['charge_flg'] != 1) {
5880                $displayFamilyAlert = true;
5881            }
5882        }
5883        // NC-4544 - check phone verification auth
5884        $verifyCount = $this->PhoneVerifyCheckLog->find('count',array(
5885            'conditions' => array(
5886                'user_id' => $this->Auth->User('id'),
5887                'status' => 0
5888            )
5889        ));
5890
5891
5892        $teacherParams = array(
5893            'type' => 'first',
5894            'args' => array(
5895                'conditions' => array(
5896                    'id' => $teacherId
5897                ),
5898                'recursive' => -1
5899            )
5900        );
5901        $teacherInfo = $this->Teacher->getTeachers($teacherParams);
5902
5903        // set localize url
5904        if (
5905            isset($get['la']) && in_array($get['la'], array_flip(Configure::read('pc_allowed_currencies'))) &&
5906            $get['la'] != Configure::read('default.user_language')
5907        ) {
5908            $localizeUrl = myTools::getUrl() . '/' . $get['la'];
5909        } else {
5910            $localizeUrl = myTools::getUrl();
5911        }
5912
5913        $corporateTypes = Configure::read('corporate_type_arr');
5914        // get live lesson coin
5915        $live_lesson_coin = 0;
5916        if (isset($teacherInfo['Teacher']['current_rank_id']) && $teacherInfo['Teacher']['current_rank_id']) {
5917             $live_lesson_coin = $this->LessonOnairsViewer->getLiveLessonCoinPrice(array(
5918                 'current_rank_id' => $teacherInfo['Teacher']['current_rank_id']
5919             ));
5920         }
5921
5922        # -don't check lesson daily limit if sapuri toS
5923        if (!$this->isStudySapuriTosUser) {
5924            // # NJ-3319
5925            $teacherStudentConnection = $this->TeacherStudentConnection->find('first', array(
5926                'conditions' => array(
5927                    'user_id' => $this->Auth->User('id'),
5928                    'teacher_id' => $teacherId
5929                ),
5930                'fields' => array(
5931                    'daily_lesson_minutes',
5932                    'daily_lesson_last_update',
5933                    'teacher_id'
5934                ),
5935                'recursive' => -1
5936            ));
5937
5938            $teacherStudentData = isset($teacherStudentConnection['TeacherStudentConnection']) ? $teacherStudentConnection['TeacherStudentConnection'] : array();
5939            if (isset($teacherStudentData['daily_lesson_minutes']) && $teacherStudentData['daily_lesson_minutes']) {
5940                $exceedDailyLimit = $this->LessonOnair->lessonStartButton(array(
5941                    'teacher_id' => $teacherId,
5942                    'teacherStudentData' => $teacherStudentData,
5943                    'counseling_flg' => isset($lessonOnair['Teacher']['counseling_flg']) ? $lessonOnair['Teacher']['counseling_flg'] : 0,
5944                    'avatar_flg' => isset($lessonOnair['Teacher']['avatar_flg']) ? $lessonOnair['Teacher']['avatar_flg'] : 0,
5945                    'nickname' => $userTable->nickname,
5946                    'admin_flg' => $userTable->admin_flg,
5947                    'isReserved' => $isReserved,
5948                    'type' => 1
5949                ));
5950            }
5951        }
5952
5953        $resetTimeLocal = TimezoneTable::computeTimeToUser(array(
5954            'time' => strtotime(date("Y-m-d 00:00:00")),
5955            'timestamp' => $this->timeDiffSecond,
5956            'format' => 'H:i'
5957        ));
5958
5959        // NJ-51 : Set delay for student lesson priority group
5960        $studentLessonPriorityTimeDelay = 0;
5961        $studentDelayInSeconds = 0;
5962
5963        if( $isNotAvatar && $isNotCounselor ) {
5964            if( $oOnair && $oOnair->status == 1 && $oOnair->user_id == null ) {
5965                $studentLessonPriorityTimeDelay = $this->User->userPriorityDelay( array( 'user_id' => $this->Auth->user('id') ) );
5966                if( $studentLessonPriorityTimeDelay ){
5967                    $studentDelayInSeconds = (int) $studentLessonPriorityTimeDelay * 1000;
5968                }
5969            }
5970        }
5971
5972        $result['studentDelayInSeconds'] = $studentDelayInSeconds;
5973
5974        $hasOtherReserved = false;
5975        //- check if reservation is not by the current teacher
5976        if ($reservedLessonData && $reservedLessonData['Teacher']['id'] != $teacherId) {
5977            $hasOtherReserved = true;
5978        }
5979
5980        $sapuriCoin = 0;
5981        if ($this->isStudySapuriUser) {
5982            $teacherParams = array(
5983                'teacher_id' => $teacherId,
5984                'current_rank_id' => $teacherInfo['Teacher']['current_rank_id']
5985            );
5986            $sapuriCoin = $this->Teacher->getStudySapuriCoin($teacherParams);
5987        }
5988
5989        # ~ check cannot emergency lesson
5990        $canEmergencyLesson = false;
5991        $emergencyBreakTime = ['status' => false];
5992        if (
5993            $isEmergencyLesson && 
5994            $this->isStudySapuriTosUser &&
5995            !$isReserved &&
5996            isset($lessonOnair[0]['can_emergency_lesson']) && 
5997            isset($lessonOnair[0]['student_no_next_reservation']) && 
5998            $lessonOnair[0]['can_emergency_lesson'] &&         # -can emergency
5999            $lessonOnair[0]['student_no_next_reservation']    # - no next reservation
6000        ) {
6001            $canEmergencyLesson = true;
6002        }
6003
6004        # ~if emergency lesson break time
6005        $currentMinutes = date("i");
6006        $currentHour = date("H");
6007        if ( $isEmergencyLesson && !$isReserved && (($currentMinutes >= 26 && $currentMinutes <= 29) || ($currentMinutes >= 56 && $currentMinutes <= 59))) {
6008            $canEmergencyLesson = false;
6009            $emergencyBreakTime['status'] = true;
6010            $emergencyBreakTime['time_span'] = '['.$currentHour.'時26分 ~ '.$currentHour.'時30分]['.$currentHour.'時56分 ~ '.$currentHour.'時00分]';
6011            $emergencyBreakTime['time_return'] = '['.$currentHour.'時30分]['.$currentHour.'時00分]';
6012        }
6013
6014        # ~no sudden lesson for sapuri toS user
6015        if ($this->isStudySapuriTosUser && !$isReserved) {
6016            $userNotEligible = true;
6017        }
6018
6019        $remainingLessonTime = 0;
6020        if( $isNotAvatar && $isNotCounselor && isset($oOnair->end_time)) {
6021            $remainingLessonTimeInSeconds = strtotime($oOnair->end_time)-strtotime('now');
6022            $remainingLessonTime = $remainingLessonTimeInSeconds <= 0 ? 0 : $remainingLessonTimeInSeconds;
6023        }
6024
6025    
6026        #NJ-18780: check for lite plan sudden lesson 
6027        // - check if reserved lesson
6028        $_userReservedNowLesson = ($reservedLessonData && $reservedLessonData['Teacher']['id'] == $teacherId) ? true : false;
6029
6030        $isNormalLitePlanUser = (in_array($user['User']['payment_plan_id'], Configure::read('payment_plan_lightplan') ) ) ? true : false;
6031
6032        if (in_array($user['User']['payment_plan_id'],Configure::read('lite_payment_plans')) && !$_userReservedNowLesson && !$isEmergencyLesson) {
6033
6034            # disable the lesson button for lite plan if it is not reserved lesson
6035            $userNotEligible = true;
6036
6037            # add if reserve is still ongoing 
6038            if ($isReserved) {
6039                $userNotEligible =false;
6040            }
6041        }
6042
6043        // NJ-29831: check if user has reserved lesson for the next 5 min
6044        $scheduleReservationData = $this->LessonSchedule->getScheduledReservationNow($studentId, $teacherInfo['Teacher']['id']);
6045        $onGoingLesson = $this->LessonOnair->hasOngoingLesson($this->Auth->user('id'));
6046        $hasLessonBeforeActualTime = false;
6047        if (isset($scheduleReservationData) && !empty($scheduleReservationData) && !$onGoingLesson) {
6048            $hasLessonBeforeActualTime = $isReserved = true;
6049        }
6050
6051        $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($user['User']['payment_plan_id']);
6052        $corporateTypeUserTable = myTools::getCoporateTypeUsingPaymentPlanId($userTable->payment_plan_id);
6053
6054        $redirectPlanUrl = '';
6055        $use7DaysTrialModal = false;
6056        $baseUrl = myTools::getUrl($this->localizeDir);
6057
6058        // if failed settlement -> paid or corporate individual (standard/premium)
6059        if (in_array($this->userMembershipType, Configure::read('membership_type_credit_retry'))) {
6060            $redirectPlanUrl = $baseUrl . '/payment/payment_credit_retry';
6061        // if free 
6062        } elseif ($this->userMembershipType == Configure::read('membership_type_plan_free')) {
6063            $redirectPlanUrl = $baseUrl . '/payment/payment_credit_charge';
6064        // if free (trial not yet conducted)
6065        } elseif ($this->userMembershipType == 13) {
6066            $userNotEligible = true;
6067            $use7DaysTrialModal = true;
6068        // if corporate company settlement failed -> standard/premium or
6069        } elseif (in_array($this->userMembershipType, Configure::read('membership_type_corporate_company_failed'))) {
6070            $redirectPlanUrl = $baseUrl . '/account/contract_information';
6071        }
6072
6073        $teacherLeaveNotice = '';
6074        $checkNextSchedule = isset($checkNextSchedule) ? $checkNextSchedule : false;
6075        $checkScheduleCurrent = isset($checkScheduleCurrent) ? $checkScheduleCurrent : false;
6076        $nextSchedule = isset($nextSchedule) ? $nextSchedule : '';
6077
6078        // NC-5554 : @modified. add trappings for meal break,
6079        // and change $canLesson['nextReserve']['start'] to mealbreak slot if has mealbreak
6080        if (
6081            (($canLesson['lessonAvailable']
6082            && !$checkNextSchedule 
6083            && $checkScheduleCurrent)
6084            || (isset($canLesson['hasMealbreakNext']) && $canLesson['hasMealbreakNext']))
6085            && !($teacherInfo['Teacher']['avatar_parent_flg'] == 1 || $teacherInfo['Teacher']['avatar_flg'] == 1)
6086            && !$isEmergencyLesson  # ~don't show in emergency page
6087            && !$this->isStudySapuriTosUser
6088            && $teacherInfo['Teacher']['home_flg'] != 1 // not home based teacher
6089            && isset($exceedDailyLimit) && !empty($exceedDailyLimit) 
6090        ) {
6091            $teacherLeaveNotice .= __d('waiting','こちらの講師は'). " ";
6092            $teacherLeaveNotice .= isset($nextSchedule) ? TimezoneTable::computeTimeToUser(array('time' => strtotime($canLesson['nextReserve']['start']), 'timestamp' => $this->timeDiffSecond, 'format' => 'h:i')) : '';
6093            $teacherLeaveNotice .= " ". __d('waiting','までのレッスンとなりますので<br>ご了承ください。');
6094        }
6095
6096
6097        // NJ-56004 - if teacher is logged in and not on standby
6098        $isRedLamp = (isset($teacherStatus1['TeacherStatus']['status']) && $teacherStatus1['TeacherStatus']['status'] == 5) ? true : $isRedLamp;
6099
6100        $canDoLive = UserTable::canJoinLiveViewing($user['User']);
6101        if (
6102            $isReserved && 
6103            (
6104                $this->isStudySapuriUser || 
6105                $this->isStudySapuriTosUser || 
6106                in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')])
6107            )
6108        ) {
6109            $canDoLive = false;
6110        }
6111
6112
6113        // set view vars
6114        $data = array(
6115            'studentLessonPriorityTimeDelayInSeconds' => $studentLessonPriorityTimeDelay,
6116            'studentDelayInSeconds' => $studentDelayInSeconds,
6117            'studentRemainingSecondsDelay' => $studentRemainingSecondsDelay,
6118            'smsThroughFlg' => isset($userTable->sms_through_flg) ? $userTable->sms_through_flg : null,
6119            'verifyCount' => $verifyCount,
6120            'userFailFlag' => isset($userFailFlag)? $userFailFlag : 0,
6121            'userDoubleCheckFlag' => isset($userDoubleCheckFlag)? $userDoubleCheckFlag : 0,
6122            'userCardCompany' => isset($userCardCompany)? $userCardCompany : 0,
6123            'lessonOnOther' => isset($lessonOnOther)? $lessonOnOther : false,
6124            'unsupportedBorwser' => $unsupportedBorwser,
6125            'userDuplicateLesson' => isset($userDuplicateLesson)? $userDuplicateLesson : false,
6126            'lessonType' => $lessonType,
6127            'device' => $device,
6128            'canLesson' => $canLesson,
6129            'userId' => isset($studentId)? $studentId : '',
6130            'teacherId' => $teacherId,
6131            'teacherStatus' => $oOnair,
6132            'isRedLamp' => $isRedLamp,
6133            'statusCheck' => array(1, 4),
6134            'canLessonTextbook' => $canLessonTextbook,
6135            'isReserved' => $isReserved,
6136            'textbookForReservationOnly' => $textbookForReservationOnly,
6137            'textbookCategoryName' => $textbookCategoryName,
6138            'userNotEligible' => isset($userNotEligible)? $userNotEligible : false,
6139            'reservedLessonData' => $reservedLessonData,
6140            'corporateLimitedPlan' => (isset($corporateType) && $corporateType == Configure::read('corporate_type.limited') ) ,// corporate limited plan
6141            'corporateLightPlan' => (isset($corporateType) && $corporateType == Configure::read('corporate_type.light') ) ,// corporate light plan
6142            'corporateIndividualUser' => $corporateIndividualUser,
6143            'corporateUserFlg' => isset($corporateUserFlg) ? $corporateUserFlg : false,
6144            'corporatePlanName' => isset($corporateTypeUserTable) ? (isset($corporateTypes[$corporateTypeUserTable]) ? $corporateTypes[$corporateTypeUserTable] : '') : '',
6145            'lessonOrangeButtonRemaining' => $lessonOrangeButtonRemaining,
6146            'checkNextSchedule' => $checkNextSchedule,
6147            'nextSchedule' => $nextSchedule,
6148            'checkScheduleCurrent' => $checkScheduleCurrent,
6149            'displayFamilyAlert' => $displayFamilyAlert,
6150            'nextReservation' => isset($nextReservation) ? $nextReservation : '',
6151            'lessonOnair' => $lessonOnair,
6152            'teacherInfo' => $teacherInfo,
6153            'localizeUrl' => $localizeUrl,
6154            'showNativeSpeakerWarning' => $showNativeSpeakerWarning,
6155            'liveViewCoin' => $live_lesson_coin,
6156            'canDoLive' => $canDoLive,
6157            'points' => $this->UsersPoint->getCurrentUserPoint($userTable->id),
6158            'exceedDailyLimit' => isset($exceedDailyLimit) ? $exceedDailyLimit : false,
6159            'resetTimeLocal' => $resetTimeLocal == "00:00" ? "24:00" : $resetTimeLocal,
6160            'hasOtherReserved' => $hasOtherReserved,
6161            'showTakeBusinessTestModal' => $showTakeBusinessTestModal,
6162            'isEmergencyLessonPage' => $isEmergencyLesson,
6163            'canEmergencyLesson' => $canEmergencyLesson,
6164            'emergencyBreakTime' => $emergencyBreakTime,
6165            'sapuriCoin' => $sapuriCoin,
6166            'isReservedCanSuddenLesson' => $isReservedCanSuddenLesson ?? false,
6167            'isReservedCanLessonViewing' => $isReservedCanLessonViewing ?? false,
6168            'canMidwayLesson' => $canMidwayLesson ?? false,
6169            'remainingLessonTime' => $remainingLessonTime,
6170            'lessonEndTime' => isset($oOnair->end_time) ? $oOnair->end_time : '',
6171            'isGuestViwer' => $isGuestViwer,
6172            'isMobileView' => $isMobileView,
6173            'isSpViewer' => $isSpViewer,
6174            'lessonStartIsNormalLitePLan' => $isNormalLitePlanUser  ? 1 : 0,
6175            'dummyLessonRoom' => $hasLessonBeforeActualTime,
6176            'isCounselor' => (isset($teacherInfo['Teacher']['counseling_flg']) && $teacherInfo['Teacher']['counseling_flg']) ? true : false,
6177            'redirectPlanUrl' => $redirectPlanUrl,
6178            'use7DaysTrialModal' => $use7DaysTrialModal,
6179            'membershipType' => $this->userMembershipType,
6180            'teacherLeaveNotice' => $teacherLeaveNotice,
6181            'isStudySapuriTosUser' => $this->isStudySapuriUser,
6182            'hasRemainingLife' => $hasRemainingLife
6183        );
6184
6185        // load lesson alert
6186        $result['lesson_alert'] = $view->element('lesson_alert', $data);
6187
6188        // load lesson start button
6189        $result['lesson_start_button'] = $view->element('lesson_start_button', $data);
6190
6191        // reserved flag
6192        $result['isReserved'] = ($isReserved) ? 1 : 0;
6193        $result['unverifiedSMS'] = empty($verifyCount) && empty($userTable->sms_through_flg) ? 1 : 0;
6194
6195        //check if Lite User
6196        $result['lessonStartIsNormalLitePLan'] = $isNormalLitePlanUser ? 1 : 0;
6197
6198        // - set to json
6199        $this->response->type('json');
6200        $this->response->body(json_encode($result));
6201
6202        // return json data
6203        return $this->response;
6204    }
6205
6206    /**
6207     * @api {post} /user/waiting/loadMoreSelfReviews loadMoreSelfReviews()
6208     * @apiName loadMoreSelfReviews
6209     * @apiGroup Waiting
6210     * @apiDescription Loads more self-reviews for a specific teacher and user in Native Camp. It returns the list of self-reviews and indicates if there are more pages available.
6211     *
6212     * @apiBody {Number} [page=2] The page number to load (default is 2).
6213     * @apiBody {String} teacherId The ID of the teacher.
6214     * @apiBody {String} userId The ID of the user.
6215     * 
6216     * @apiSuccess {String} list The HTML list of self-reviews.
6217     * @apiSuccess {Boolean} hasNext Indicates whether there are more pages of self-reviews available.
6218     *
6219     * @apiSuccessExample {json} Success-Response:
6220     *     {
6221     *         "list": "<li>Review 1</li><li>Review 2</li>",
6222     *         "hasNext": true
6223     *     }
6224     *
6225     * @apiError {String} status The status of the request (NG).
6226     * @apiError {String} message The error message.
6227     *
6228     * @apiErrorExample {json} Error-Response:
6229     *     {
6230     *         "status": "NG",
6231     *         "message": "Invalid request."
6232     *     }
6233     * 
6234     * @apiSampleRequest off
6235     */
6236    public function loadMoreSelfReviews() {
6237        $this->autoRender = false;
6238        $list = '';
6239        if ($this->request->is('ajax')) {
6240            $page = isset($this->request->data['page']) ?  $this->request->data['page'] : 2;
6241          $teacherId = isset($this->request->data['teacherId']) ? $this->request->data['teacherId'] : 0;
6242          $userId = isset($this->request->data['userId']) ? $this->request->data['userId'] : 0;
6243            //reviews
6244      $selfReviews = $this->getUserReviews($userId, $teacherId, $page);
6245            $view = new View($this, false);
6246            $list = $view->element('self_comment_list', array('selfReviews' => $selfReviews));
6247        }
6248        return json_encode(
6249            array(
6250                'list' => $list,
6251                'hasNext' => $this->params['paging']['UsersClassEvaluation']['nextPage']
6252            ));
6253    }
6254
6255    /**
6256    * get own user review count and reviews
6257    * @param int user_id
6258    */
6259    private function getUserReviews($userId, $teacherId, $page = 1) {
6260        $this->paginate = array(
6261            'fields' => array(
6262                'UsersClassEvaluation.id',
6263                'UsersClassEvaluation.rate',
6264                'UsersClassEvaluation.user_comment',
6265                'UsersClassEvaluation.created'
6266            ),
6267            'conditions' => array(
6268                    'UsersClassEvaluation.teacher_id' => $teacherId,
6269                    'UsersClassEvaluation.user_id' => $userId,
6270                    'UsersClassEvaluation.rate IS NOT NULL',
6271                ),
6272            'page' => $page,
6273            'limit' => $this->selfReviewLimit,
6274            'order' => 'UsersClassEvaluation.created DESC',
6275            'recursive' => -1
6276        );
6277        return $this->paginate('UsersClassEvaluation');
6278    }
6279
6280    //Retrieves the reservation and cancellation statistics for a specific teacher in Native Camp. It returns the count of reservations and cancellations for the current and previous month, as well as the cancellation rates.
6281    public function getReserveAndCancelled($teacherId) {
6282        //params
6283        $param = array('teacher_id' => $teacherId);
6284
6285        //get count finish reservation and cancelled reservations
6286        $thisMonthReservation = $this->LessonSchedule->getCurrentMonthReservationCount($param);
6287        $lastMonthReservation = $this->LessonSchedule->getLastMonthReservationCount($param);
6288        $thisMonthReservedCancellation = $this->LessonScheduleCancel->getCurrentReservationCancelledCount($param);
6289        $lastMonthReservedCancellation = $this->LessonScheduleCancel->getLastReservationCancelledCount($param);
6290
6291        //get divisors
6292        $lastMonth = strtotime("first day of previous month");
6293        $thisMonthLSDivisor = $this->LessonSchedule->getCancellationRateDivisor($teacherId);
6294        $lastMonthLSDivisor = $this->LessonSchedule->getCancellationRateDivisor($teacherId, $lastMonth);
6295        $thisMonthLSCDivisor = $this->LessonScheduleCancel->getCancellationRateDivisor($teacherId);
6296        $lastMonthLSCDivisor = $this->LessonScheduleCancel->getCancellationRateDivisor($teacherId, $lastMonth);
6297
6298        $thisMonthDivisor = $thisMonthReservation + $thisMonthLSDivisor + $thisMonthLSCDivisor;
6299        $lastMonthDivisor = $lastMonthReservation + $lastMonthLSDivisor + $lastMonthLSCDivisor;
6300
6301        $thisMonthCancellationPercentage = ($thisMonthDivisor == 0) ? 0 : (int)(($thisMonthReservedCancellation / $thisMonthDivisor) * 100);
6302        $lastMonthCancellationPercentage = ($lastMonthDivisor == 0) ? 0 : (int)(($lastMonthReservedCancellation / $lastMonthDivisor) * 100);
6303
6304        return array(
6305            'this_month_reserved' => $thisMonthReservation,
6306            'last_month_reserved' => $lastMonthReservation,
6307            'this_month_cancelled' => $thisMonthReservedCancellation,
6308            'last_month_cancelled' => $lastMonthReservedCancellation,
6309            'this_month_cancellation_rate' => $thisMonthCancellationPercentage,
6310            'last_month_cancellation_rate' => $lastMonthCancellationPercentage
6311        );
6312    }
6313
6314    /**
6315    * shows the orange button after the lesson end
6316    * @param int $userId
6317    * @param int $teacherId
6318    * @param boolean $userNotEligible
6319    * @param boolean $unsupportedBorwser
6320    * @param boolean $canLesson
6321    * @return int $lessonOrangeButtonRemaining
6322    ***/
6323    private function triggerOrangeButton($userId='', $teacherId='', $userNotEligible=false, $unsupportedBorwser=false, $canLesson=false) {
6324        $lessonOrangeButtonRemaining = false;
6325        $secondsRemaining = $this->LessonOnairsLog->getLastLessonSecondsRemaining($userId, $teacherId);
6326        if ($secondsRemaining && !$userNotEligible && !$unsupportedBorwser && $canLesson) {
6327            $lessonOrangeButtonRemaining = $secondsRemaining;
6328        }
6329        return $lessonOrangeButtonRemaining;
6330    }
6331
6332    /**
6333     * @api {post} /user/waiting/deleteLessonOnair deleteLessonOnair()
6334     * @apiName deleteLessonOnair
6335     * @apiGroup Waiting
6336     * @apiDescription Deletes the ongoing lesson on-air information for the authenticated user in Native Camp. It forcefully terminates the lesson if necessary.
6337     *
6338     * @apiBody {Number} [lesson_finish=6] The lesson finish status (default is 6 for force terminate).
6339     * 
6340     * @apiSuccess {Boolean} result Indicates whether the lesson on-air information was successfully deleted.
6341     *
6342     * @apiSuccessExample {json} Success-Response:
6343     *     {
6344     *         "result": true
6345     *     }
6346     *
6347     * @apiError {String} status The status of the request (NG).
6348     * @apiError {String} message The error message.
6349     *
6350     * @apiErrorExample {json} Error-Response:
6351     *     {
6352     *         "status": "NG",
6353     *         "message": "Invalid request."
6354     *     }
6355     * 
6356     * @apiSampleRequest off
6357     */
6358    public function deleteLessonOnair () {
6359        $this->autoRender = false;
6360
6361        // get lesson onair
6362        $lessonOnair = $this->LessonOnair->find('first', array(
6363            'fields' => array(
6364                'LessonOnair.id',
6365                'LessonOnair.lesson_type',
6366                'LessonOnair.leave_lesson'
6367            ),
6368            'conditions' => array(
6369                'LessonOnair.user_id' => $this->Auth->user('id')
6370            ),
6371            'recursive' => -1
6372        ));
6373
6374        // if don't have ongoing lesson onair information
6375        if (!$lessonOnair) {
6376            $this->log("[delete_lesson_onair] has no lesson onair", "debug");
6377            return;
6378        }
6379
6380        // if reserve lesson
6381        if (
6382            !empty($lessonOnair) && // if has lesson onair
6383            $lessonOnair['LessonOnair']['lesson_type'] == 2 // if lesson type is reserve lesson
6384        ) {
6385            // if not yet leave lesson -> force to leave lesson
6386            if ($lessonOnair['LessonOnair']['leave_lesson'] == 0) {
6387                $force_leave_lesson = LessonOnairTable::studentForceLeaveLesson(['lesson_onair_id' => $lessonOnair['LessonOnair']['id']]);
6388                
6389                if (!$force_leave_lesson) {
6390                    throw new Exception('error: Unable to forcefully terminate ongoing lesson ->' . json_encode($lessonOnair));
6391                }
6392            }
6393            // if not normal lesson
6394        } elseif (isset($lessonOnair["LessonOnair"]["lesson_type"]) && $lessonOnair["LessonOnair"]["lesson_type"] != 1) {
6395            throw new Exception('error: not a normal lesson ->' . json_encode($lessonOnair));
6396        }
6397
6398        // log
6399        $this->log("[delete_lesson_onair] deleting lesson onair -> " . json_encode($lessonOnair), "debug");
6400        
6401        $lesson_finish_status = !empty($this->request->data['lesson_finish']) ? $this->request->data['lesson_finish'] : 6; // set lesson finish status, or else set to 6 = force terminate default
6402
6403        // delete lesson oanir
6404        $res = LessonOnairTable::delete($lessonOnair['LessonOnair']['id'], array(), $lesson_finish_status);
6405        
6406        return json_encode(array('result' => $res ? true : false));
6407    }
6408
6409    /**
6410    * get online teachers first page
6411    */
6412    private function getTeacherOnlineList() {
6413        $returnData = array();
6414        $conditionArr = array();
6415        $conditionResult = $this->getSearchCondition();
6416        $conditionResult['conditions'] = array($conditionResult['conditions']);
6417
6418        $commonTeacherStatusParams = array(
6419            'page_display' => 'searchPage',
6420            'query_conditions' => $conditionResult
6421        );
6422        $data = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
6423        
6424        //clear teacher id
6425        $this->Session->delete('waiting-loadedTID');
6426        //save new teacher id
6427        if ($data) {
6428            $teacherId = array();
6429            foreach ($data['TeacherOnlineList'] as $teacher) {
6430                $teacherId[] = $teacher['Teacher']['id'];
6431            }
6432            $this->Session->write('waiting-loadedTID', $teacherId);
6433        }
6434        $returnData['teacherRecordCount'] = $data['teacherRecordCount'];
6435        $returnData['teacherData'] = $data['TeacherOnlineList'];
6436        $returnData['limitGauge'] = $conditionResult['limitGauge']+1;
6437        $returnData['limit'] = $conditionResult['limitCondition'];
6438        return $returnData;
6439    }
6440
6441    /**
6442    * get default search condition
6443    */
6444    private function getSearchCondition() {
6445        //default sort
6446        $sortCondition =  array(
6447            '(select if(count(*) > 0, 1, 0)
6448               FROM lesson_onairs
6449              WHERE teacher_id = Teacher.id AND status = 1 AND connect_flg = 1 LIMIT 1) desc',
6450
6451            '(if ((select if (count(*) > 0, 1, 0)
6452            from teacher_status
6453            where teacher_id = Teacher.id and status = 4 LIMIT 1)
6454
6455            OR
6456
6457            (select if (count(*) > 0, 1, 0)
6458            from lesson_onairs
6459            where teacher_id = Teacher.id and status <> 1 and connect_flg = 1 LIMIT 1), 3, 0)) desc',
6460
6461            'TeacherWeeklyRating.ratings desc',
6462
6463            'Teacher.lesson_count desc',
6464
6465            'Teacher.name asc'
6466        );
6467        //get block teachers id
6468        $blockList = BlockListTable::getBlocks($this->Auth->User('id'), false, 'all');
6469
6470        //default condition
6471        $conditions = array(
6472            'Teacher.id NOT IN' => $blockList,
6473            'Teacher.status' => 1,
6474            'Teacher.admin_flg' => 0,
6475            'Teacher.counseling_flg' => 0,
6476            'Teacher.last_login_time >=' => date('Y-m-d 00:00:00', strtotime('-59 days')),
6477            'LessonOnair.status = 1',
6478            'LessonOnair.connect_flg = 1'
6479        );
6480
6481        // NC-7031
6482        $conditions["AND"]["OR"] = array(
6483            array("Teacher.avatar_parent_flg" => 0, "Teacher.avatar_flg" => 0) // normal teacher
6484        );
6485        //stealth teacher
6486        if ($this->Cookie->read('stealth.setting') != 'on') {
6487            $conditions['Teacher.stealth_flg <>'] = 1;
6488        }
6489
6490        return array(
6491            'conditions' => $conditions,
6492            'sortCondition' => $sortCondition,
6493            'limitGauge' => 1,
6494            'pageLimit' => 80,
6495            'limitCondition' => 80,
6496            'defaultPageLimit' => 80,
6497            'seeMorePageLimit' => 18,
6498            'force_index' => 'FORCE INDEX(last_login_time)'
6499        );
6500    }
6501
6502    //not used function
6503    public function getApologyList($teacher_id = null) {
6504        $cancellesson = $this->LessonScheduleCancel->find('all', array(
6505            'conditions'=>array(
6506                'LessonScheduleCancel.user_id' => $this->Auth->user('id'),
6507                'LessonScheduleCancel.teacher_id' => $teacher_id,
6508#                'LessonScheduleCancel.lesson_time > ' => date('Y-m-d H:i:s'),
6509                'LessonScheduleCancel.status' => Configure::read('reserve_cancel_status_list'),//3 - admin cancel, 4 - system cancel, [24-28] - teacher cancellation, [29-33] - admin cancellation
6510                'LessonScheduleCancel.apology_show' => 1
6511            ),
6512            'fields' => array('LessonScheduleCancel.id', 'LessonScheduleCancel.lesson_time', 'LessonScheduleCancel.user_id','Teacher.id', 'Teacher.name'),
6513            'joins' => array(
6514                    array(
6515                        'type' => 'INNER',
6516                        'table' => 'teachers',
6517                        'alias' => 'Teacher',
6518                        'conditions' => array('Teacher.id = LessonScheduleCancel.teacher_id')
6519                        )
6520                ),
6521            'order' => 'LessonScheduleCancel.id desc'
6522        ));
6523
6524        return $cancellesson;
6525    }
6526
6527    /**
6528     * reservation limit
6529     * @return int
6530     * 1: warning 4th reservation
6531     * 2: 20 lesson reservation only
6532     * 3: 4 reservation only for each teacher
6533     * 4: cancellation limit
6534     * 5: complimentary plan
6535     * 6: corporate light max lesson limit
6536     * 7: lesson request max limit
6537     * 8: eligible for lesson request
6538     */ 
6539
6540     /**
6541     * @api {post} /user/waiting/limit-warning limitwarning()
6542     * @apiName limitwarning
6543     * @apiGroup Waiting
6544     * @apiDescription Checks for reservation limits and warnings for the authenticated user in Native Camp. It returns the status and any relevant messages or limits.
6545     *
6546     * @apiBody {String} [userId] The ID of the user (optional if fromCorporateManagement or fromSapuriTos is set).
6547     * @apiBody {Boolean} [fromCorporateManagement] Indicates if the request is from corporate management.
6548     * @apiBody {Boolean} [fromSapuriTos] Indicates if the request is from Sapuri TOS.
6549     * 
6550     * @apiSuccess {String} status The status of the request (OK or NG).
6551     * @apiSuccess {Number} content The content of the response.
6552     * @apiSuccess {Number} cancelCount The count of cancellations by the user.
6553     *
6554     * @apiSuccessExample {json} Success-Response:
6555     *     {
6556     *         "status": "OK",
6557     *         "content": 1,
6558     *         "cancelCount": 2
6559     *     }
6560     *
6561     * @apiError {String} status The status of the request (NG).
6562     * @apiError {Number} content The content of the response.
6563     * @apiError {Number} cancelCount The count of cancellations by the user.
6564     *
6565     * @apiErrorExample {json} Error-Response:
6566     *     {
6567     *         "status": "NG",
6568     *         "content": 0,
6569     *         "cancelCount": 0
6570     *     }
6571     * 
6572     * @apiSampleRequest off
6573     */
6574    public function limitwarning() {
6575        $this->autoRender = false;
6576
6577        if ($this->request->is('post')) {
6578            $post = $this->request->data;
6579
6580            // NC-8336
6581            if (
6582                isset($post['userId']) &&
6583                (isset($post['fromCorporateManagement']) || isset($post['fromSapuriTos']))
6584            ) {
6585                // nothing to do
6586            } else {
6587                $post['userId'] = $this->Auth->user('id');
6588                $post['user'] = $this->sharedUserData['User'];
6589            }
6590
6591            $post['nc_terminal_type'] = 1; // pc
6592            $post['timeDiffSecond'] = $this->timeDiffSecond;
6593 
6594            // open tunnel
6595            myTools::initializeApiTunnel(['ReservationController']);
6596
6597            // initialize controller
6598            $rc = new ReservationController();
6599
6600            // set data
6601            $rc->params = $post;
6602
6603            // process
6604            return $rc->limitWarning();
6605        } else {
6606            return json_encode([
6607                'status' => 'NG',
6608                'content' => 0,
6609                'cancelCount' => 0
6610            ]);
6611        }
6612    }
6613
6614    /**
6615     * @api {post} /user/waiting/updatedScheduleColor updatedScheduleColor()
6616     * @apiName updatedScheduleColor
6617     * @apiGroup Waiting
6618     * @apiDescription Retrieves the updated schedule color information for the authenticated user in Native Camp. It returns the dates when lessons are not available.
6619     *
6620     * @apiBody {String} teacherId The ID of the teacher.
6621     * 
6622     * @apiSuccess {Object} disabledSchedule The disabled schedule information.
6623     * @apiSuccess {Boolean} disabledSchedule.disableAll Indicates whether all dates are disabled.
6624     * @apiSuccess {String[]} disabledSchedule.disabledDays The list of disabled dates.
6625     *
6626     * @apiSuccessExample {json} Success-Response:
6627     *     {
6628     *         "disableAll": false,
6629     *         "disabledDays": [
6630     *             "2023-12-01",
6631     *             "2023-12-02"
6632     *         ]
6633     *     }
6634     *
6635     * @apiError {String} status The status of the request (NG).
6636     * @apiError {String} message The error message.
6637     *
6638     * @apiErrorExample {json} Error-Response:
6639     *     {
6640     *         "status": "NG",
6641     *         "message": "Invalid request."
6642     *     }
6643     * 
6644     * @apiSampleRequest off
6645     */
6646    public function updatedScheduleColor() {
6647        $this->autoRender = false;
6648        if ($this->request->is('ajax')) {
6649            $teacherId = $this->request->data['teacherId'];
6650
6651            // NJ-18780 : 
6652            $_paymentPlanID = isset($this->sharedUserData['User']['payment_plan_id']) ? $this->sharedUserData['User']['payment_plan_id'] : null;
6653            $isNormalLitePlanUser = (in_array($_paymentPlanID, Configure::read('lite_payment_plans') ) ) ? true : false;
6654
6655            $disabledSchedule = $this->LessonSchedule->getDisabledDaysPC(array(
6656                'userId' => $this->Auth->user('id'),
6657                'teacherId' => $teacherId,
6658                'timeDiff' => $this->timeDiff,
6659                'isNormalLitePlanUser' => $isNormalLitePlanUser
6660            ));
6661            return json_encode($disabledSchedule);
6662        }
6663    }
6664
6665    /**
6666     * @api {post} /user/waiting/getAvatarDisabledDates getAvatarDisabledDates()
6667     * @apiName getAvatarDisabledDates
6668     * @apiGroup Waiting
6669     * @apiDescription Retrieves the disabled dates for avatar lessons for the authenticated user in Native Camp. It returns the dates when avatar lessons are not available.
6670     *
6671     * @apiBody {String} teacherId The ID of the avatar teacher.
6672     * 
6673     * @apiSuccess {Object} disabledSchedule The disabled schedule information.
6674     * @apiSuccess {Boolean} disabledSchedule.disableAll Indicates whether all dates are disabled.
6675     * @apiSuccess {String[]} disabledSchedule.disabledDays The list of disabled dates.
6676     *
6677     * @apiSuccessExample {json} Success-Response:
6678     *     {
6679     *         "disableAll": false,
6680     *         "disabledDays": [
6681     *             "2023-12-01",
6682     *             "2023-12-02"
6683     *         ]
6684     *     }
6685     *
6686     * @apiError {String} status The status of the request (NG).
6687     * @apiError {String} message The error message.
6688     *
6689     * @apiErrorExample {json} Error-Response:
6690     *     {
6691     *         "status": "NG",
6692     *         "message": "Invalid request."
6693     *     }
6694     * 
6695     * @apiSampleRequest off
6696     */
6697    public function getAvatarDisabledDates() {
6698        $this->autoRender = false;
6699        if ($this->request->is('ajax')) {
6700            $teacherId = $this->request->data['teacherId'];
6701            $getAvatarParams = array(
6702                "avatar_id" => $teacherId,
6703                "user_id" => $this->Auth->user('id'),
6704                "stealth_flg" => $this->Cookie->read('stealth.setting')
6705            );
6706
6707            // NJ-18780 : 
6708            $_paymentPlanID = isset($this->sharedUserData['User']['payment_plan_id']) ? $this->sharedUserData['User']['payment_plan_id'] : null;
6709            $isNormalLitePlanUser = (in_array($_paymentPlanID, Configure::read('lite_payment_plans'))) ? true : false;
6710
6711            $avatarTeacherIds = $this->Teacher->getAvatarTeacherId($getAvatarParams);
6712            $disabledSchedule = $this->LessonSchedule->getDisabledDaysPC(array(
6713                'userId' => $this->Auth->user('id'),
6714                'teacherId' => $avatarTeacherIds,
6715                'timeDiff' => $this->timeDiff,
6716                'isNormalLitePlanUser' => $isNormalLitePlanUser
6717            ));
6718            return json_encode($disabledSchedule);
6719        }
6720    }
6721
6722    /**
6723     * @api {get} /user/sp/counselor_detail/ sp_counselor()
6724     * @apiName sp_counselor
6725     * @apiGroup Waiting
6726     * @apiDescription Redirects the user to the counselor detail page.
6727     *
6728     * @apiSuccess {String} url The URL to which the user is redirected.
6729     *
6730     * @apiSuccessExample {json} Success-Response:
6731     *     {
6732     *         "url": "https://example.com/user/counselor_detail"
6733     *     }
6734     *
6735     * @apiError {String} status The status of the request (NG).
6736     * @apiError {String} message The error message.
6737     *
6738     * @apiErrorExample {json} Error-Response:
6739     *     {
6740     *         "status": "NG",
6741     *         "message": "Invalid request."
6742     *     }
6743     * 
6744     * @apiSampleRequest off
6745     */
6746    public function sp_counselor() {
6747        return $this->redirect(myTools::getUrl() . '/user/counselor_detail', 301);
6748    }
6749
6750    /**
6751     * @api {get} /user/:language/counselor_detail counselor()
6752     * @apiName counselor
6753     * @apiGroup Waiting
6754     * @apiDescription Retrieves the counselor details for the authenticated user in Native Camp. It returns various information about the user's counselor status, lesson history, and more.
6755     *
6756     * @apiParam {String} language The language code for the page.
6757     * 
6758     * @apiSuccess {Object} teacher The counselor information.
6759     * @apiSuccess {String} teacher.id The ID of the counselor.
6760     * @apiSuccess {String} teacher.name The name of the counselor.
6761     * @apiSuccess {String} teacher.image_url The URL of the counselor's image.
6762     * @apiSuccess {Boolean} isFav Indicates whether the counselor is favorited by the user.
6763     * @apiSuccess {Object} teacherFavsColors The favorite colors for the counselor.
6764     * @apiSuccess {Number} favoriteCount The count of users who have favorited the counselor.
6765     * @apiSuccess {Boolean} isHide Indicates whether the counselor is hidden by the user.
6766     * @apiSuccess {Boolean} isLoggedIn Indicates whether the user is logged in.
6767     * @apiSuccess {Object} disabledSchedule The disabled schedule information.
6768     * @apiSuccess {Boolean} disabledSchedule.disableAll Indicates whether all dates are disabled.
6769     * @apiSuccess {String[]} disabledSchedule.disabledDays The list of disabled dates.
6770     * @apiSuccess {Number} reviewsCount The count of reviews for the counselor.
6771     * @apiSuccess {String} userId The ID of the user.
6772     * @apiSuccess {Object} counselingTable The counseling table information.
6773     * @apiSuccess {Boolean} unsupportedBrowser Indicates whether the user's browser is unsupported.
6774     * @apiSuccess {String} user_lang The native language of the user.
6775     * @apiSuccess {Object} userTimezoneData The user's timezone data.
6776     * @apiSuccess {String} userTimezoneData.city_eng The city in English.
6777     * @apiSuccess {String} userTimezoneData.utc_offset The UTC offset.
6778     * @apiSuccess {Number} userTimezoneData.country_code_id The country code ID.
6779     * @apiSuccess {String} countryTimezone The country name based on the user's timezone.
6780     * @apiSuccess {Object} counselorLampStatus The counselor lamp status.
6781     * @apiSuccess {String} userCurrentTime The current time of the user.
6782     * @apiSuccess {Boolean} login Indicates whether the user is logged in.
6783     * @apiSuccess {Boolean} canReport Indicates whether the user can report the counselor.
6784     * @apiSuccess {Object} keep_memo The memo kept by the user for the counselor.
6785     * @apiSuccess {String} keep_memo.id The ID of the memo.
6786     * @apiSuccess {String} keep_memo.memo The memo text.
6787     * @apiSuccess {Number} order The order of the reviews.
6788     * @apiSuccess {String} chatHash The chat hash for the lesson.
6789     * @apiSuccess {Object[]} counselorLessonHistory The lesson history of the counselor.
6790     * @apiSuccess {Object} counselorLessonHistory.LessonOnairsLog The lesson on-air log.
6791     * @apiSuccess {String} counselorLessonHistory.LessonOnairsLog.start_time The start time of the lesson.
6792     * @apiSuccess {String} formattedLatestLessonDate The formatted date of the latest lesson.
6793     * @apiSuccess {Number} lessonHistoryCount The count of lessons in the lesson history.
6794     * @apiSuccess {Object} latestUserLesson The latest lesson taken by the user with the counselor.
6795     * @apiSuccess {Object} latestUserLesson.LessonOnairsLog The lesson on-air log.
6796     * @apiSuccess {String} latestUserLesson.LessonOnairsLog.start_time The start time of the lesson.
6797     * @apiSuccess {Object} user The user information.
6798     * @apiSuccess {String} user.id The ID of the user.
6799     * @apiSuccess {String} user.name The name of the user.
6800     * @apiSuccess {String} user.email The email of the user.
6801     *
6802     * @apiSuccessExample {json} Success-Response:
6803     *     HTTP/1.1 200 OK
6804     *     {
6805     *         "teacher": {
6806     *             "id": "123",
6807     *             "name": "Counselor Name",
6808     *             "image_url": "http://example.com/image.jpg"
6809     *         },
6810     *         "isFav": true,
6811     *         "teacherFavsColors": {...},
6812     *         "favoriteCount": 10,
6813     *         "isHide": false,
6814     *         "isLoggedIn": true,
6815     *         "disabledSchedule": {
6816     *             "disableAll": false,
6817     *             "disabledDays": [
6818     *                 "2023-12-01",
6819     *                 "2023-12-02"
6820     *             ]
6821     *         },
6822     *         "reviewsCount": 5,
6823     *         "userId": "123",
6824     *         "counselingTable": {...},
6825     *         "unsupportedBrowser": false,
6826     *         "user_lang": "en",
6827     *         "userTimezoneData": {
6828     *             "city_eng": "Tokyo",
6829     *             "utc_offset": "+09:00",
6830     *             "country_code_id": 81
6831     *         },
6832     *         "countryTimezone": "Japan",
6833     *         "counselorLampStatus": {...},
6834     *         "userCurrentTime": "2023/12/01 10:00",
6835     *         "login": true,
6836     *         "canReport": true,
6837     *         "keep_memo": {
6838     *             "id": "1",
6839     *             "memo": "This is a memo."
6840     *         },
6841     *         "order": 0,
6842     *         "chatHash": "example_chat_hash",
6843     *         "counselorLessonHistory": [
6844     *             {
6845     *                 "LessonOnairsLog": {
6846     *                     "start_time": "2023-12-01 10:00:00"
6847     *                 }
6848     *             }
6849     *         ],
6850     *         "formattedLatestLessonDate": "2023-12-01 (Fri)",
6851     *         "lessonHistoryCount": 5,
6852     *         "latestUserLesson": {
6853     *             "LessonOnairsLog": {
6854     *                 "start_time": "2023-12-01 10:00:00"
6855     *             }
6856     *         },
6857     *         "user": {
6858     *             "id": "123",
6859     *             "name": "John Doe",
6860     *             "email": "john.doe@test.com"
6861     *         }
6862     *     }
6863     *
6864     * @apiError {String} status The status of the request (NG).
6865     * @apiError {String} message The error message.
6866     *
6867     * @apiErrorExample {json} Error-Response:
6868     *     HTTP/1.1 400 Bad Request
6869     *     {
6870     *         "status": "NG",
6871     *         "message": "Invalid request."
6872     *     }
6873     * 
6874     * @apiSampleRequest off
6875     */
6876    public function counselor() {
6877        // NC-9875 start
6878        if ($this->localizeDir == 'ko' || $this->localizeDir == 'zh-tw' || $this->localizeDir == 'vi' || $this->localizeDir =='pt-br') {
6879            return $this->redirect(myTools::getUrl());
6880        }
6881
6882        $where = array(
6883            'user_id' => $this->Auth->user('id'),
6884            'teacher_id' => Configure::read('default_counselor_detail')
6885        );
6886
6887        if ((BlockListTable::isUserBlocked($where) == true) || ($this->BlockList->isTeacherHide($where) == true)) {
6888            return $this->redirect('/mypage');
6889        }
6890
6891        // NC-6615 check if user can report the teacher
6892        $canReport = true;
6893        if (isset($this->sharedUserData['User'])) {
6894            $userData = new UserTable($this->sharedUserData['User']);
6895            $userMemberTypeCantReportTeacher = Configure::read('user_member_type.cant_report_teacher');
6896            $userMemberTypeCanDoCounselingArr = Configure::read('counselor_allowed_membership_index_data');
6897            $canReport = $userData->getMembershipTypeIndex();
6898            $membershipIndex = $canReport;
6899            $canReport = in_array($canReport, $userMemberTypeCantReportTeacher) ? false : true;
6900
6901            //NJ-9489 - redirect to top page if payment type is not allowed
6902            $_userPaymentPlan = $this->sharedUserData['User']['payment_plan_id'];
6903
6904            // NJ-1454 - redirect to top page if membership type is not allowed
6905            if( !in_array($membershipIndex,$userMemberTypeCanDoCounselingArr) ) {
6906                return $this->redirect(myTools::getUrl());
6907            }
6908
6909            // NJ-9489 - redirect to top page if payment plan is not allowed
6910            if( 
6911                !$_userPaymentPlan ||
6912                in_array($_userPaymentPlan,Configure::read('counselor.not_allowed_payment_plan_id'))
6913             ) {
6914                return $this->redirect(myTools::getUrl());
6915            }
6916        }
6917
6918        // NC-9875 end
6919        $counselor = $this->Teacher->getDefaultCounselorData();
6920        $this->set('teacher', $counselor);
6921
6922        //NJ-20069 counselor
6923        if(!$this->RequestHandler->isMobile()) {
6924            $lessonHistory = $this->LessonSchedule->latestCounselorLessonHistory($this->Auth->user('id'), null);
6925            $latestUserLesson = ($lessonHistory['lessonHistory'][0]);
6926            $lessonHistoryCount = count($lessonHistory['lessonHistory']);
6927            
6928            $formattedLatestLessonData = "";
6929            if(!empty($latestUserLesson))
6930            $formattedLatestLessonDate = date('Y-m-d',strtotime($latestUserLesson['LessonOnairsLog']['start_time'])). " (" . date('D',strtotime($latestUserLesson['LessonOnairsLog']['start_time'])) . ") ";
6931            
6932            $this->set('counselorLessonHistory', $lessonHistory['lessonHistory']);
6933            $this->set('formattedLatestLessonDate', $formattedLatestLessonDate);
6934            $this->set('lessonHistoryCount', $lessonHistoryCount);
6935            $this->set('latestUserLesson', $latestUserLesson);
6936        }
6937        
6938        //test
6939
6940
6941
6942        # favorite
6943        $where = array(
6944            'UsersFavorite.user_id'     => $this->Auth->user('id'),
6945            'UsersFavorite.teacher_id'     => Configure::read('default_counselor_detail')
6946        );
6947        $isFav = $this->UsersFavorite->find('count', array('conditions' => $where));
6948        $this->set('isFav', $isFav);
6949        $favIds = $isFav ? [Configure::read('default_counselor_detail')] : [];
6950        $teacherFavColor = $this->UsersFavoriteCategoriesTeacher->getColorFavTeacherByIds(['user_id' => $this->Auth->user('id'), 'teacher_ids' => $favIds]);
6951        $teacherFavsColors = $this->UsersFavoriteCategoriesTeacher->parseToHexColor([
6952            'favIds' => $favIds,
6953            'favIdsTeacherCategory' => $teacherFavColor
6954        ]);
6955        $this->set('teacherFavsColors', $teacherFavsColors);
6956        # count favorite users
6957        $where = array(
6958            'UsersFavorite.teacher_id'  => Configure::read('default_counselor_detail')
6959        );
6960        $favoriteCount = $this->UsersFavorite->find('count', array('conditions' => $where));
6961        $this->set('favoriteCount', $favoriteCount);
6962
6963        # is teacher hide
6964        $where = array(
6965            'user_id' => $this->Auth->user('id'),
6966            'teacher_id' => Configure::read('default_counselor_detail')
6967        );
6968        $isHide = $this->BlockList->isTeacherHide($where);
6969        $this->set('isHide', $isHide);
6970
6971        //NC-7984 start
6972        $this->set('isLoggedIn', $this->Auth->loggedIn());
6973        $this->counselorLatestLessonHistory($this->Auth->user('id'));
6974        //NC-7984 end
6975
6976        $userId = $this->Auth->user('id');
6977        $counselingTable = $this->CounselingTable;
6978        // - get disabled dates
6979        $counselorIds = $this->Teacher->getCounselorId();
6980        $disabledSchedule = $this->LessonSchedule->getDisabledDays(array(
6981            'userId' => $userId,
6982            'teacherId' => $counselorIds,
6983            'timeDiff' => $this->timeDiff
6984        ));
6985        $this->set('showNoticeMaxLimit', (isset($disabledSchedule['disableAll']) ? $disabledSchedule['disableAll'] : false));
6986        $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir);
6987        $options['language_id'] = $reviewLanguage[0];
6988        $options['not_language_ids'] = $reviewLanguage[1] ?? null;
6989        $reviewsCount = $this->UsersClassEvaluation->getCommentCount($counselorIds, $options);
6990
6991        // - set data to view
6992        $setData = array(
6993            'reviewsCount' => $reviewsCount,
6994            'userId' => $userId,
6995            'disabledSchedule' => json_encode($disabledSchedule),
6996            'counselingTable' => $counselingTable
6997        );
6998        $unsupportedBrowser = false;
6999        $browser = $this->request->header('User-Agent');
7000
7001        if (preg_match('/(OPR|Opera)/i', $browser)) { 
7002            $unsupportedBrowser = true;
7003        } elseif (preg_match('/(Edg|Edge|Chrome|Firefox|Safari)/i', $browser)) { 
7004            $unsupportedBrowser = false;
7005        } else { 
7006            $unsupportedBrowser = true;
7007        }
7008
7009        $this->set('unsupportedBrowser', $unsupportedBrowser);
7010        $this->set($setData);
7011
7012        if (isset($this->sharedUserData['User'])) {
7013            $this->set('user_lang', $this->sharedUserData['User']['native_language2']);
7014        }
7015
7016        # get user timezone
7017        $user_timezone_id = (isset($this->sharedUserData['User']['timezone_id'])) ? $this->sharedUserData['User']['timezone_id'] : 203;
7018        $user_timezone_data = $this->Timezone->find('first',
7019            array(
7020                'fields' => array(
7021                    'Timezone.city_eng',
7022                    'Timezone.utc_offset',
7023                    'Timezone.country_code_id'
7024                ),
7025                'conditions' => array(
7026                    'Timezone.id' => $user_timezone_id
7027                ),
7028                'recursive' => -1
7029            )
7030        );
7031
7032        // - NJ-3653 get country
7033        $countryTimezone = null;
7034        if (!empty($user_timezone_data) && $user_timezone_data['Timezone']['country_code_id']) {
7035            // - Get all country Code
7036            $countryOptions = $this->Timezone->countryOptions();
7037
7038            $countryCodeId = $user_timezone_data['Timezone']['country_code_id'];
7039            $countryName = $countryOptions[$countryCodeId]['country_name'];
7040
7041            if (isset($countryName) && $countryName) {
7042                $countryTimezone = $countryName;
7043            }
7044        }
7045
7046        // NJ-20272:get counselor lamp status 
7047        $counselorLampStatus = $this->Teacher->getCounselorLampStatus();
7048
7049        $this->set('countryTimezone', $countryTimezone);
7050        $this->set('userTimezoneData', $user_timezone_data);
7051        $this->set('counselorLampStatus',$counselorLampStatus);
7052
7053        #user time
7054        $datetime = date('Y-m-d H:i:s');
7055        $localTime = $this->displayTime;
7056        // NJ-29496
7057        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) { 
7058            $formattedDate = date('d/m/Y G:i', $localTime);
7059        } else {
7060            $formattedDate = date('Y/m/d G:i', $localTime);
7061        }
7062        $this->set('userCurrentTime', $formattedDate);    
7063        $this->set('login', $this->Auth->loggedIn());
7064        $this->set('canReport', $canReport);
7065
7066        $params = array(
7067            'this' => $this,
7068            'forceMobile' => false,
7069            'spView' => '/Mobile/Teacher/counselor_detail',
7070            'view' => '/Waiting/counselor_detail',
7071            'layout' => 'mobile',
7072            'mobile' => null,
7073            'pc' => null
7074        );
7075
7076        //NC-7603 get keep memo
7077        $this->UsersMemo->openDBReplica();
7078        $getKeepMemo = $this->UsersMemo->find('first', array(
7079            'fields' => array(
7080                'id',
7081                'memo'
7082            ),
7083            'conditions' => array(
7084                'user_id' => $this->Auth->user('id'),
7085                'is_counselor' => true
7086            ),
7087            'order' => array('id DESC'),
7088        ));
7089        $this->UsersMemo->closeDBReplica();
7090
7091        // - set keep memo
7092        $this->set('keep_memo', $getKeepMemo);
7093
7094        //set meta for teacher or counselor image 
7095        $counselorObject = new TeacherTable($counselor['Teacher']);
7096        $_teacherImgUrl = $counselorObject->getImageUrl();
7097
7098        //if has image 
7099        if ($_teacherImgUrl) {
7100
7101            //check if teacher has no image 
7102            if (empty($counselorObject->image_url) || !$counselorObject->image_url) {
7103                $defaultTeacherImg = myTools::getUrl() . '/teacher/img/no_profile_img.jpg';
7104                $_teacherImgUrl = ($_teacherImgUrl == $defaultTeacherImg) ? $_teacherImgUrl : $defaultTeacherImg;
7105            }
7106
7107            $this->set('meta_teacher_img',$_teacherImgUrl);        
7108        }
7109
7110        
7111        // - set review order
7112        $this->set('order', $this->Cookie->read('teacherReviewOrder') ?? 0);
7113
7114        // class evaluation
7115        if ($this->request->query('chatHash')) {
7116            $chatHash = $this->request->query('chatHash');
7117
7118            // Check if chatHash is valid
7119            $this->LessonOnairsLog->openDBReplica();
7120            $allData = $this->LessonOnairsLog->find('first', $this->checkHash('LessonOnairsLog',$chatHash));
7121            $this->LessonOnairsLog->closeDBReplica();
7122
7123            if(!$allData) { // if LessonOnairsLog's chat_hash returns null/empty , retrieve record from lessonOnair
7124                $this->LessonOnair->openDBReplica();
7125                $allData = $this->LessonOnair->find('first', $this->checkHash('LessonOnair',$chatHash));
7126                $this->LessonOnair->closeDBReplica();
7127
7128                if(!$allData) {
7129                    return $this->redirect(array('controller' => 'home', 'action' => 'index', 'home'));
7130                }
7131            }
7132
7133            if(!empty($this->sharedUserData['User'])){
7134                // - campaing stamps
7135                $this->getActiveCampaignStampData();
7136            }
7137
7138            $this->set('chatHash', $chatHash);
7139        }
7140        $this->set('counselor_teacher_detail', 1);
7141
7142        // - get user information
7143        $this->User->openDBReplica();
7144        $this->User->recursive = -1;
7145        $data = $this->User->findById($userId);
7146        $this->User->closeDBReplica();
7147
7148        $user = isset($data['User'])?$data['User']: null;
7149        $this->set('counselorObject', $counselorObject);
7150        $this->set('user', $user);
7151        myTools::render($params);
7152    }
7153
7154    /**
7155     * @api {get} /user/customersupport_detail customersupport()
7156     * @apiName customersupport
7157     * @apiGroup Waiting
7158     * @apiDescription Retrieves the customer support details for the authenticated user in Native Camp. It returns various information about the user's customer support status, lesson history, and more.
7159     * 
7160     * @apiSuccess {Boolean} isHide Indicates whether the teacher is hidden by the user.
7161     * @apiSuccess {Boolean} isLoggedIn Indicates whether the user is logged in.
7162     * @apiSuccess {Number} reviewsCount The count of reviews for the counselor.
7163     * @apiSuccess {String} userId The ID of the user.
7164     * @apiSuccess {Object} disabledSchedule The disabled schedule information.
7165     * @apiSuccess {Boolean} disabledSchedule.disableAll Indicates whether all dates are disabled.
7166     * @apiSuccess {String[]} disabledSchedule.disabledDays The list of disabled dates.
7167     * @apiSuccess {Object} counselingTable The counseling table information.
7168     * @apiSuccess {Boolean} unsupportedBrowser Indicates whether the user's browser is unsupported.
7169     * @apiSuccess {String} user_lang The native language of the user.
7170     * @apiSuccess {Object} userTimezoneData The user's timezone data.
7171     * @apiSuccess {String} userTimezoneData.city_eng The city in English.
7172     * @apiSuccess {String} userTimezoneData.utc_offset The UTC offset.
7173     * @apiSuccess {Number} userTimezoneData.country_code_id The country code ID.
7174     * @apiSuccess {String} countryTimezone The country name based on the user's timezone.
7175     * @apiSuccess {Object} counselorLampStatus The counselor lamp status.
7176     * @apiSuccess {String} userCurrentTime The current time of the user.
7177     * @apiSuccess {Boolean} login Indicates whether the user is logged in.
7178     * @apiSuccess {Boolean} canReport Indicates whether the user can report the teacher.
7179     * @apiSuccess {Object} keep_memo The memo kept by the user for the teacher.
7180     * @apiSuccess {String} keep_memo.id The ID of the memo.
7181     * @apiSuccess {String} keep_memo.memo The memo text.
7182     * @apiSuccess {Number} order The order of the reviews.
7183     * @apiSuccess {String} chatHash The chat hash for the lesson.
7184     * @apiSuccess {Object[]} counselorLessonHistory The lesson history of the counselor.
7185     * @apiSuccess {Object} counselorLessonHistory.LessonOnairsLog The lesson on-air log.
7186     * @apiSuccess {String} counselorLessonHistory.LessonOnairsLog.start_time The start time of the lesson.
7187     * @apiSuccess {String} formattedLatestLessonDate The formatted date of the latest lesson.
7188     * @apiSuccess {Number} lessonHistoryCount The count of lessons in the lesson history.
7189     * @apiSuccess {Object} latestUserLesson The latest lesson taken by the user with the counselor.
7190     * @apiSuccess {Object} latestUserLesson.LessonOnairsLog The lesson on-air log.
7191     * @apiSuccess {String} latestUserLesson.LessonOnairsLog.start_time The start time of the lesson.
7192     * @apiSuccess {Object} user The user information.
7193     * @apiSuccess {String} user.id The ID of the user.
7194     * @apiSuccess {String} user.name The name of the user.
7195     * @apiSuccess {String} user.email The email of the user.
7196     *
7197     * @apiSuccessExample {json} Success-Response:
7198     *     {
7199     *         "isHide": false,
7200     *         "isLoggedIn": true,
7201     *         "reviewsCount": 10,
7202     *         "userId": "123",
7203     *         "disabledSchedule": {
7204     *             "disableAll": false,
7205     *             "disabledDays": [
7206     *                 "2023-12-01",
7207     *                 "2023-12-02"
7208     *             ]
7209     *         },
7210     *         "counselingTable": {...},
7211     *         "unsupportedBrowser": false,
7212     *         "user_lang": "en",
7213     *         "userTimezoneData": {
7214     *             "city_eng": "Tokyo",
7215     *             "utc_offset": "+09:00",
7216     *             "country_code_id": 81
7217     *         },
7218     *         "countryTimezone": "Japan",
7219     *         "counselorLampStatus": {...},
7220     *         "userCurrentTime": "2023/12/01 10:00",
7221     *         "login": true,
7222     *         "canReport": true,
7223     *         "keep_memo": {
7224     *             "id": "1",
7225     *             "memo": "This is a memo."
7226     *         },
7227     *         "order": 0,
7228     *         "chatHash": "example_chat_hash",
7229     *         "counselorLessonHistory": [
7230     *             {
7231     *                 "LessonOnairsLog": {
7232     *                     "start_time": "2023-12-01 10:00:00"
7233     *                 }
7234     *             }
7235     *         ],
7236     *         "formattedLatestLessonDate": "2023-12-01 (Fri)",
7237     *         "lessonHistoryCount": 5,
7238     *         "latestUserLesson": {
7239     *             "LessonOnairsLog": {
7240     *                 "start_time": "2023-12-01 10:00:00"
7241     *             }
7242     *         },
7243     *         "user": {
7244     *             "id": "123",
7245     *             "name": "John Doe",
7246     *             "email": "john.doe@test.com"
7247     *         }
7248     *     }
7249     *
7250     * @apiError {String} status The status of the request (NG).
7251     * @apiError {String} message The error message.
7252     *
7253     * @apiErrorExample {json} Error-Response:
7254     *     {
7255     *         "status": "NG",
7256     *         "message": "Invalid request."
7257     *     }
7258     * 
7259     * @apiSampleRequest off
7260     */
7261    public function customersupport() {
7262
7263        // NC-9875 start
7264        if ($this->localizeDir == 'ko' || $this->localizeDir == 'zh-tw' || $this->localizeDir == 'vi') {
7265            return $this->redirect(myTools::getUrl());
7266        }
7267
7268        $isCustomerSupportUser = $this->UsersDetail->isCustomerSupportUser($this->Auth->user('id'));
7269        if(!$isCustomerSupportUser){
7270            return $this->redirect('/mypage');
7271        }
7272
7273        // NJ-54011: Check if user is Free trial not conducted yet.
7274        if ($this->userMembershipType == 13) {
7275            $this->set('membershipType', $this->userMembershipType);
7276        }
7277
7278        $where = array(
7279            'user_id' => $this->Auth->user('id'),
7280            'teacher_id' => Configure::read('default_counselor_detail')
7281        );
7282
7283        if ((BlockListTable::isUserBlocked($where) == true) || ($this->BlockList->isTeacherHide($where) == true)) {
7284            return $this->redirect('/mypage');
7285        }
7286
7287        // NC-6615 check if user can report the teacher
7288        $canReport = true;
7289        if (isset($this->sharedUserData['User'])) {
7290            $userData = new UserTable($this->sharedUserData['User']);
7291            $userMemberTypeCantReportTeacher = Configure::read('user_member_type.cant_report_teacher');
7292            $userMemberTypeCanDoCounselingArr = Configure::read('counselor_allowed_membership_index_data');
7293            $canReport = $userData->getMembershipTypeIndex();
7294            $membershipIndex = $canReport;
7295            $canReport = in_array($canReport, $userMemberTypeCantReportTeacher) ? false : true;
7296            //NJ-9489 - redirect to top page if payment type is not allowed
7297            $_userPaymentPlan = $this->sharedUserData['User']['payment_plan_id'];
7298        }
7299
7300        # is teacher hide
7301        $where = array(
7302            'user_id' => $this->Auth->user('id'),
7303            'teacher_id' => Configure::read('default_customer_support_detail')
7304        );
7305        $isHide = $this->BlockList->isTeacherHide($where);
7306        $this->set('isHide', $isHide);
7307
7308        $counselor = $this->Teacher->getDefaultCustomerSupportDetail();
7309
7310        //NC-7984 start
7311        $this->set('isLoggedIn', $this->Auth->loggedIn());
7312        $this->counselorLatestLessonHistory($this->Auth->user('id'));
7313        //NC-7984 end
7314
7315        $userId = $this->Auth->user('id');
7316        $counselingTable = $this->CounselingTable;
7317        // - get disabled dates
7318        $counselorIds = $this->Teacher->getCounselorId();
7319        $disabledSchedule = $this->LessonSchedule->getDisabledDays(array(
7320            'userId' => $userId,
7321            'teacherId' => $counselorIds,
7322            'timeDiff' => $this->timeDiff
7323        ));
7324        $this->set('showNoticeMaxLimit', (isset($disabledSchedule['disableAll']) ? $disabledSchedule['disableAll'] : false));
7325        $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir);
7326        $options['language_id'] = $reviewLanguage[0];
7327        $options['not_language_ids'] = $reviewLanguage[1] ?? null;
7328        $reviewsCount = $this->UsersClassEvaluation->getCommentCount($counselorIds, $options);
7329
7330        // - set data to view
7331        $setData = array(
7332            'reviewsCount' => $reviewsCount,
7333            'userId' => $userId,
7334            'disabledSchedule' => json_encode($disabledSchedule),
7335            'counselingTable' => $counselingTable
7336        );
7337        $unsupportedBrowser = false;
7338        $browser =  $this->request->header('User-Agent');
7339
7340        if (preg_match('/(OPR|Opera)/i', $browser)) { 
7341            $unsupportedBrowser = true;
7342        } elseif (preg_match('/(Edg|Edge|Chrome|Firefox|Safari)/i', $browser)) { 
7343            $unsupportedBrowser = false;
7344        } else { 
7345            $unsupportedBrowser = true;
7346        }
7347        $this->set('unsupportedBrowser', $unsupportedBrowser);
7348        $this->set($setData);
7349
7350        if (isset($this->sharedUserData['User'])) {
7351            $this->set('user_lang', $this->sharedUserData['User']['native_language2']);
7352        }
7353
7354        # get user timezone
7355        $user_timezone_id = (isset($this->sharedUserData['User']['timezone_id'])) ? $this->sharedUserData['User']['timezone_id'] : 203;
7356        $user_timezone_data = $this->Timezone->find('first',
7357            array(
7358                'fields' => array(
7359                    'Timezone.city_eng',
7360                    'Timezone.utc_offset',
7361                    'Timezone.country_code_id'
7362                ),
7363                'conditions' => array(
7364                    'Timezone.id' => $user_timezone_id
7365                ),
7366                'recursive' => -1
7367            )
7368        );
7369
7370        // - NJ-3653 get country
7371        $countryTimezone = null;
7372        if (!empty($user_timezone_data) && $user_timezone_data['Timezone']['country_code_id']) {
7373            // - Get all country Code
7374            $countryOptions = $this->Timezone->countryOptions();
7375
7376            $countryCodeId = $user_timezone_data['Timezone']['country_code_id'];
7377            $countryName = $countryOptions[$countryCodeId]['country_name'];
7378
7379            if (isset($countryName) && $countryName) {
7380                $countryTimezone = $countryName;
7381            }
7382        }
7383
7384        // NJ-20272:get counselor lamp status 
7385        $counselorLampStatus = $this->Teacher->getCounselorLampStatus();
7386
7387        $this->set('countryTimezone', $countryTimezone);
7388        $this->set('userTimezoneData', $user_timezone_data);
7389        $this->set('counselorLampStatus',$counselorLampStatus);
7390
7391        #user time
7392        $datetime = date('Y-m-d H:i:s');
7393        $localTime = $this->displayTime;
7394        // NJ-29496
7395        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) { 
7396            $formattedDate = date('d/m/Y G:i', $localTime);
7397        } else {
7398            $formattedDate = date('Y/m/d G:i', $localTime);
7399        }
7400        $this->set('userCurrentTime', $formattedDate);    
7401        $this->set('login', $this->Auth->loggedIn());
7402        $this->set('canReport', $canReport);
7403
7404        $params = array(
7405            'this' => $this,
7406            'forceMobile' => false,
7407            'spView' => '/Mobile/Teacher/counselor_detail',
7408            'view' => '/Waiting/customersupport_detail',
7409            'layout' => 'mobile',
7410            'mobile' => null,
7411            'pc' => null
7412        );
7413
7414        //NC-7603 get keep memo
7415        $this->UsersMemo->openDBReplica();
7416        $getKeepMemo = $this->UsersMemo->find('first', array(
7417            'fields' => array(
7418                'id',
7419                'memo'
7420            ),
7421            'conditions' => array(
7422                'user_id' => $this->Auth->user('id'),
7423                'teacher_id' => Configure::read('default_customer_support_detail')
7424            ),
7425            'order' => array('id DESC'),
7426        ));
7427        $this->UsersMemo->closeDBReplica();
7428
7429        // - set keep memo
7430        $this->set('keep_memo', $getKeepMemo);
7431
7432        // - set review order
7433        $this->set('order', $this->Cookie->read('teacherReviewOrder') ?? 0);
7434
7435        // class evaluation
7436        if ($this->request->query('chatHash')) {
7437            $chatHash = $this->request->query('chatHash');
7438
7439            // Check if chatHash is valid
7440            $this->LessonOnairsLog->openDBReplica();
7441            $allData = $this->LessonOnairsLog->find('first', $this->checkHash('LessonOnairsLog',$chatHash));
7442            $this->LessonOnairsLog->closeDBReplica();
7443
7444            if(!$allData) { // if LessonOnairsLog's chat_hash returns null/empty , retrieve record from lessonOnair
7445                $this->LessonOnair->openDBReplica();
7446                $allData = $this->LessonOnair->find('first', $this->checkHash('LessonOnair',$chatHash));
7447                $this->LessonOnair->closeDBReplica();
7448
7449                if(!$allData) {
7450                    return $this->redirect(array('controller' => 'home', 'action' => 'index', 'home'));
7451                }
7452            }
7453
7454            if(!empty($this->sharedUserData['User'])){
7455                // - campaing stamps
7456                $this->getActiveCampaignStampData();
7457            }
7458
7459            $this->set('chatHash', $chatHash);
7460        }
7461
7462        $lessonHistory = $this->LessonSchedule->latestCounselorLessonHistory($this->Auth->user('id'), null, true);
7463        $latestUserLesson = ($lessonHistory['lessonHistory'][0]);
7464        $lessonHistoryCount = count($lessonHistory['lessonHistory']);
7465        $lessonHistoryCount = 0;
7466        
7467        $formattedLatestLessonData = "";
7468        if(!empty($latestUserLesson))
7469        $formattedLatestLessonDate = date('Y-m-d',strtotime($latestUserLesson['LessonOnairsLog']['start_time'])). " (" . date('D',strtotime($latestUserLesson['LessonOnairsLog']['start_time'])) . ") ";
7470        
7471        $this->set('counselorLessonHistory', $lessonHistory['lessonHistory']);
7472        $this->set('formattedLatestLessonDate', $formattedLatestLessonDate);
7473        $this->set('lessonHistoryCount', $lessonHistoryCount);
7474        $this->set('latestUserLesson', $latestUserLesson);
7475
7476        // - get user information
7477        $this->User->openDBReplica();
7478        $this->User->recursive = -1;
7479        $data = $this->User->findById($userId);
7480        $this->User->closeDBReplica();
7481
7482        $user = isset($data['User'])?$data['User']: null;
7483        $this->set('teacher', $counselor);
7484        $this->set('user', $user);
7485        $this->set('isCustomerSupportUser', true);
7486         myTools::render($params);
7487        
7488    }
7489
7490    //end of customer support func
7491
7492
7493
7494    /**
7495     * @api {post} /user/waiting/counselingGetDisabledDates counselingGetDisabledDates()
7496     * @apiName counselingGetDisabledDates
7497     * @apiGroup Waiting
7498     * @apiDescription Retrieves the disabled dates for counseling sessions for the authenticated user in Native Camp. It returns the dates when counseling sessions are not available.
7499     *
7500     * @apiBody {String} userId The ID of the user.
7501     * 
7502     * @apiSuccess {Object} disabledSchedule The disabled schedule information.
7503     * @apiSuccess {Boolean} disabledSchedule.disableAll Indicates whether all dates are disabled.
7504     * @apiSuccess {String[]} disabledSchedule.disabledDays The list of disabled dates.
7505     *
7506     * @apiSuccessExample {json} Success-Response:
7507     *     {
7508     *         "disableAll": false,
7509     *         "disabledDays": [
7510     *             "2023-12-01",
7511     *             "2023-12-02"
7512     *         ]
7513     *     }
7514     *
7515     * @apiError {String} status The status of the request (NG).
7516     * @apiError {String} message The error message.
7517     *
7518     * @apiErrorExample {json} Error-Response:
7519     *     {
7520     *         "status": "NG",
7521     *         "message": "Invalid request."
7522     *     }
7523     * 
7524     * @apiSampleRequest off
7525     */
7526    public function counselingGetDisabledDates() {
7527        $this->autoRender = false;
7528        if ($this->request->is('ajax')) {
7529            $data = $this->request->data;
7530            // - get disabled dates
7531            $counselorIds = $this->Teacher->getCounselorId();
7532            $disabledSchedule = $this->LessonSchedule->getDisabledDays(array(
7533                'userId' => $data['userId'],
7534                'teacherId' => $counselorIds,
7535                'timeDiff' => $this->timeDiff
7536            ));
7537            return json_encode($disabledSchedule);
7538        }
7539    }
7540
7541    /**
7542     * @api {post} /user/waiting/counselorSlots counselorSlots()
7543     * @apiName counselorSlots
7544     * @apiGroup Waiting
7545     * @apiDescription Retrieves the available slots for counseling sessions for the authenticated user in Native Camp. It returns the available slots and their states.
7546     *
7547     * @apiBody {String} userId The ID of the user.
7548     * @apiBody {Boolean} [ifForCancellation=false] Indicates whether the request is for cancellation.
7549     * 
7550     * @apiSuccess {Object} schedules The schedules of available slots.
7551     * @apiSuccess {String} schedules.day The day of the week.
7552     * @apiSuccess {String} schedules.d The day of the month.
7553     * @apiSuccess {String} schedules.m The month.
7554     * @apiSuccess {String} schedules.y The year.
7555     * @apiSuccess {Object} schedules.slots The slots for the day.
7556     * @apiSuccess {Number} schedules.slots.open_counselor The number of open counselors.
7557     * @apiSuccess {Number} schedules.slots.state The state of the slot (1: Reserved by user, 2: Reserved by others, 3: Not available, 4: Fully booked, 5: Can't reserve due to limit, 6: Not available within 10 minutes, 7: Available).
7558     * @apiSuccess {Number} schedules.slots.hour The hour of the slot.
7559     * @apiSuccess {Number} schedules.slots.minute The minute of the slot.
7560     * @apiSuccess {Boolean} schedules.slots.is_reserve Indicates whether the slot is reserved by the user.
7561     * @apiSuccess {Number} [schedules.slots.limited_plan_reservation] Indicates whether the slot is limited plan reservation (if applicable).
7562     *
7563     * @apiSuccessExample {json} Success-Response:
7564     *     {
7565     *         "schedules": {
7566     *             "12/01": {
7567     *                 "day": "(月)",
7568     *                 "d": "01",
7569     *                 "m": "12",
7570     *                 "y": "2023",
7571     *                 "slots": {
7572     *                     "10:00": {
7573     *                         "open_counselor": 2,
7574     *                         "state": 7,
7575     *                         "hour": 10,
7576     *                         "minute": 0,
7577     *                         "is_reserve": false
7578     *                     },
7579     *                     "10:30": {
7580     *                         "open_counselor": 1,
7581     *                         "state": 1,
7582     *                         "hour": 10,
7583     *                         "minute": 30,
7584     *                         "is_reserve": true
7585     *                     }
7586     *                 }
7587     *             }
7588     *         }
7589     *     }
7590     *
7591     * @apiError {String} status The status of the request (NG).
7592     * @apiError {String} message The error message.
7593     *
7594     * @apiErrorExample {json} Error-Response:
7595     *     {
7596     *         "status": "NG",
7597     *         "message": "Invalid request."
7598     *     }
7599     * 
7600     * @apiSampleRequest off
7601     */
7602    public function counselorSlots() {
7603        // $this->autoRender = false;
7604        $data = $this->request->data;
7605        $ifForCancellation = (isset($data['ifForCancellation']) && $data['ifForCancellation']) ? true : false;
7606        $user_id = isset($data['userId']) ? $data['userId'] : '';
7607        $this->set('userId', $user_id);
7608        $nowTime = time();
7609        $userTime = $this->displayTime;
7610        $start_date = date('Y-m-d H:i', $nowTime);
7611        $corporateLightUser = false;
7612        $corporateLimitedUser = false;
7613        $slots = array(
7614            'show_caution_flg' => 0,
7615            'start_date' => $start_date,
7616            'states' => NULL
7617        );
7618        // check corporate user
7619        $getCorporateType = $this->User->find("first",array(
7620                "conditions" => array( "User.id" => $user_id ),
7621                "fields" => array("User.payment_plan_id"),
7622                "recursive" => -1,
7623            )
7624        );
7625        
7626        if ($getCorporateType && isset($getCorporateType["User"]["payment_plan_id"]) ) {
7627            $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($getCorporateType["User"]["payment_plan_id"]);
7628            
7629            $corporateLimitedUser = ($corporateType == Configure::read("corporate_type.limited"));
7630            $corporateLightUser = ($corporateType == Configure::read("corporate_type.light"));
7631        }
7632        $this->set('corporateLimitedUser', $corporateLimitedUser);
7633        $this->set('corporateLightUser', $corporateLightUser);
7634        // - if reservation exceeds cancellation already
7635        $sharedUserDataCorporateType = myTools::getCoporateTypeUsingPaymentPlanId($this->sharedUserData['User']['payment_plan_id']);
7636        $slots['show_caution_flg'] = ($this->LessonSchedule->reservationCautionFlag(array('userId' => $user_id))) ? 1 : 0;
7637        $counselorIds = $this->Teacher->getCounselorId();
7638        $result = $this->LessonSchedule->getCounselorSlots(array(
7639            'counselor_ids' => $counselorIds,
7640            'user_id' => $user_id,
7641            'start_day' => $start_date,
7642            'include_past' => true,
7643            'corporateLimitedUser' => $corporateLimitedUser,
7644            'corporateLightUser' => (isset($sharedUserDataCorporateType) && $sharedUserDataCorporateType == Configure::read("corporate_type.light")) ? true : false
7645        ));
7646
7647        $weekday = array( __d('waiting','(日)'), __d('waiting','(月)'), __d('waiting','(火)'), __d('waiting','(水)'), __d('waiting','(木)'), __d('waiting','(金)'), __d('waiting','(土)') );
7648        $openSlots = array();
7649        $schedules = array();
7650
7651        if (!$result['error']) {
7652            // - get days
7653            for ($i=0; $i<=7; $i++) {
7654                $cTime = strtotime("+" . $i . " days", $userTime);
7655                $schedDate = date('m/d', $cTime);
7656                $schedules[$schedDate] = array(
7657                    'day' => $weekday[date("w", $cTime)],
7658                    'd' => date('d', $cTime),
7659                    'm' => date('m', $cTime),
7660                    'y' => date('Y', $cTime)
7661                );
7662            }
7663
7664            // - arrange open_slot
7665            foreach ($result['openSlotData'] as $slot) {
7666                $shiftTime = TimezoneTable::computeTimeToUser(array(
7667                    'time' => strtotime($slot['ShiftWorkOn']['lesson_time']),
7668                    'timestamp' => $this->timeDiffSecond
7669                ));
7670                $openSlots[date('Y-m-d H:i:s', $shiftTime)] = $slot[0]['shiftCount'];
7671                $formattedLessonTime = date('Y-m-d H:i', $shiftTime);
7672                $lessonHour = date('H', $shiftTime);
7673                $lessonMinute = date('i', $shiftTime);
7674                $lessonDateTime = explode(' ', $formattedLessonTime);
7675                $lessonDate = isset($lessonDateTime[0]) ? $lessonDateTime[0] : '';
7676                $lessonDate = date('m/d', strtotime($lessonDate));
7677                $lessonTime = isset($lessonDateTime[1]) ? $lessonDateTime[1] : '';
7678
7679                // - state 7 : Available
7680                $state = 7;
7681
7682                //check before 10minutes
7683                if ((strtotime($slot['ShiftWorkOn']['lesson_time']) - strtotime($start_date)) <= 600) {
7684                    $state = 6;
7685                }
7686
7687                $schedules[$lessonDate]['slots'][$lessonTime] = array(
7688                    'open_counselor' => intval($slot[0]['shiftCount']),
7689                    'state' => $state,
7690                    'hour' => $lessonHour,
7691                    'minute' => $lessonMinute
7692                );
7693
7694                if ($corporateLimitedUser && isset($slot['TeacherRankCoin'])) {
7695                    $schedules[$lessonDate]['slots'][$lessonTime]['limited_plan_reservation'] = $slot['TeacherRankCoin']['limited_plan_reservation'];
7696                }
7697            }
7698
7699            // - counselor ids
7700            $counselorsIds = !empty($counselorIds) ? array_values($counselorIds) : array();
7701            // - counselor reservations
7702            foreach ($result['reservationData'] as $reservation) {
7703                //get timestamp adjusted to user timezone
7704                $unixUserLessonTime = TimezoneTable::computeTimeToUser(array(
7705                    'time' => strtotime($reservation['LessonSchedule']['lesson_time']),
7706                    'timestamp' => $this->timeDiffSecond
7707                ));
7708                $timeIndex = date('Y-m-d H:i:s', $unixUserLessonTime);
7709                $formattedUserLessonTime = date('Y-m-d H:i', $unixUserLessonTime);
7710
7711                $lessonHour = date('H', $unixUserLessonTime);
7712                $lessonMinute = date('i', $unixUserLessonTime);
7713                $lessonDateTime = explode(' ', $formattedUserLessonTime);
7714                $lessonDate = isset($lessonDateTime[0]) ? $lessonDateTime[0] : '';
7715                $lessonDate = date('m/d', strtotime($lessonDate));
7716                $lessonTime = isset($lessonDateTime[1]) ? $lessonDateTime[1] : '';
7717
7718                // - if my reservation
7719                if ($reservation['LessonSchedule']['user_id'] == $user_id) {
7720                    if (!in_array($reservation['LessonSchedule']['teacher_id'], $counselorsIds) && !empty($openSlots[$timeIndex])) {
7721                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 2;
7722                    } elseif (!in_array($reservation['LessonSchedule']['teacher_id'], $counselorsIds) && empty($openslot[$timeIndex])) {
7723                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 3;
7724                    } else {
7725                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 1;
7726                        $schedules[$lessonDate]['slots'][$lessonTime]['hour'] = $lessonHour;
7727                        $schedules[$lessonDate]['slots'][$lessonTime]['minute'] = $lessonMinute;
7728                    }
7729
7730                    $schedules[$lessonDate]['slots'][$lessonTime]['is_reserve'] = true;
7731
7732                // - if not my reservations
7733                } elseif ((isset($schedules[$lessonDate]['slots'][$lessonTime]['state']) && $schedules[$lessonDate]['slots'][$lessonTime]['state'] != 1)) {
7734                    $openSlots[$timeIndex]--;
7735
7736                    # to prevent the schedule of the current user being overriden by other users schedules
7737                    if (isset($schedules[$lessonDate]['slots'][$lessonTime]['state']) && isset($schedules[$lessonDate]['slots'][$lessonTime]['is_reserve']) && $schedules[$lessonDate]['slots'][$lessonTime]['is_reserve'] ) {
7738                        continue;
7739                    }
7740
7741                    if (
7742                        (isset($disabledSchedule['disableAll']) && $disabledSchedule['disableAll'])
7743                        || (!empty($disabledSchedule['disabledDays']) && in_array(date('Y-m-d', $unixUserLessonTime), $disabledSchedule['disabledDays']))
7744                        && (!empty($openSlots[$timeIndex]) && $schedules[$formattedLessonTime]['state'] >= 5)
7745                    ) {
7746                        $openSlots[$timeIndex]--;
7747                        // - state 5 : can't reserve because of reservation limit
7748                        $schedules[$lessonDate]['slots'][$lessonTime] = array(
7749                            'state' => 5,
7750                            'open_counselor' => intval($openSlots[$timeIndex]),
7751                            'hour' => $lessonHour,
7752                            'minute' => $lessonMinute
7753                        );
7754
7755                    } elseif (!empty($openSlots[$timeIndex]) && $schedules[$lessonDate]['slots'][$lessonTime]['state'] >= 4) {
7756                        // - state 7 : Available
7757                        $schedules[$lessonDate]['slots'][$lessonTime] = array(
7758                            'state' => 7,
7759                            'open_counselor' => intval($openSlots[$timeIndex]),
7760                            'hour' => $lessonHour,
7761                            'minute' => $lessonMinute
7762                        );
7763                    } elseif (
7764                        isset($openSlots[$timeIndex])
7765                        && $openSlots[$timeIndex] <= 0
7766                        && (
7767                            isset($schedules[$formattedLessonTime]['state'])
7768                            && $schedules[$formattedLessonTime]['state'] >= 4
7769                            || empty($schedules[$formattedLessonTime]['state'])
7770                        )
7771                    ) {
7772                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 4;
7773                        $schedules[$lessonDate]['slots'][$lessonTime]['hour'] = $lessonHour;
7774                        $schedules[$lessonDate]['slots'][$lessonTime]['minute'] = $lessonMinute;
7775                    }
7776                }
7777            }
7778
7779            if ($ifForCancellation) {
7780                $this->autoRender = false;
7781                return json_encode($schedules);
7782            }
7783            $this->set('schedules', $schedules);
7784        }
7785    }
7786
7787    /**
7788     * @api {post} /user/waiting/avatarSlots avatarSlots()
7789     * @apiName avatarSlots
7790     * @apiGroup Waiting
7791     * @apiDescription Retrieves the available slots for avatar lessons for the authenticated user in Native Camp. It returns the schedule and availability of the slots.
7792     *
7793     * @apiBody {String} teacherId The ID of the avatar teacher.
7794     * @apiBody {Boolean} [ifForCancellation] Indicates whether the request is for cancellation.
7795     * @apiBody {String} userId The ID of the user.
7796     * 
7797     * @apiSuccess {Object} schedules The schedule and availability of the slots.
7798     * @apiSuccess {String} schedules.day The day of the week.
7799     * @apiSuccess {String} schedules.d The day of the month.
7800     * @apiSuccess {String} schedules.m The month.
7801     * @apiSuccess {String} schedules.y The year.
7802     * @apiSuccess {Object} schedules.slots The slots for each day.
7803     * @apiSuccess {Number} schedules.slots.open_avatar The number of open avatar slots.
7804     * @apiSuccess {Number} schedules.slots.state The state of the slot (1: Reserved by user, 2: Reserved by another user, 3: Reserved by another user and not available, 4: No open slots, 5: Can't reserve because of reservation limit, 6: Can't reserve because it's within 5 minutes, 7: Available).
7805     * @apiSuccess {Number} schedules.slots.hour The hour of the slot.
7806     * @apiSuccess {Number} schedules.slots.minute The minute of the slot.
7807     * @apiSuccess {Object} [schedules.slots.teacherData] The data of the teacher for the slot.
7808     * @apiSuccess {Object} [schedules.slots.ownTeacherData] The data of the user's own teacher for the slot.
7809     * @apiSuccess {Boolean} schedules.slots.is_reserve Indicates whether the slot is reserved by the user.
7810     * @apiSuccess {String} schedules.slots.teacher_id The ID of the teacher for the slot.
7811     * @apiSuccess {Object} campaignPeriod The campaign period for the avatar teacher.
7812     * @apiSuccess {String[]} times The available times for the slots.
7813     *
7814     * @apiSuccessExample {json} Success-Response:
7815     *     {
7816     *         "schedules": {
7817     *             "12/01": {
7818     *                 "day": "(月)",
7819     *                 "d": "01",
7820     *                 "m": "12",
7821     *                 "y": "2023",
7822     *                 "slots": {
7823     *                     "10:00": {
7824     *                         "open_avatar": 2,
7825     *                         "state": 7,
7826     *                         "hour": 10,
7827     *                         "minute": 0
7828     *                     },
7829     *                     "10:30": {
7830     *                         "open_avatar": 1,
7831     *                         "state": 1,
7832     *                         "hour": 10,
7833     *                         "minute": 30,
7834     *                         "ownTeacherData": {
7835     *                             "id": "123",
7836     *                             "name": "John Doe",
7837     *                             "image": "https://www.nativecamp.net/img/teacher/123.jpg"
7838     *                         }
7839     *                     }
7840     *                 }
7841     *             }
7842     *         },
7843     *         "campaignPeriod": {...},
7844     *         "times": ["00:00", "00:30", "01:00", ...]
7845     *     }
7846     *
7847     * @apiError {String} status The status of the request (NG).
7848     * @apiError {Number} content The content of the response (0: No issues).
7849     *
7850     * @apiErrorExample {json} Error-Response:
7851     *     {
7852     *         "status": "NG",
7853     *         "content": 0
7854     *     }
7855     * 
7856     * @apiSampleRequest off
7857     */
7858    public function avatarSlots() {
7859        
7860        $data = $this->request->data;
7861        $teacherId = isset($data['teacherId']) ? $data['teacherId'] : '';
7862        $ifForCancellation = (isset($data['ifForCancellation']) && $data['ifForCancellation']) ? true : false;
7863        $user_id = isset($data['userId']) ? $data['userId'] : '';
7864        $this->set('userId', $user_id);
7865        $this->set('currentAvatarId', $teacherId);
7866        $nowTime = time();
7867        $userTime = $this->displayTime;
7868        $start_date = date('Y-m-d H:i', $nowTime);
7869        $corporateLightUser = false;
7870        $corporateLimitedUser = false;
7871        $slots = array(
7872            'show_caution_flg' => 0,
7873            'start_date' => $start_date,
7874            'states' => NULL
7875        );
7876        // check corporate user
7877        $getCorporateType = $this->User->find("first",array(
7878                "conditions" => array( "User.id" => $user_id ),
7879                "fields" => array("User.payment_plan_id"),
7880                "recursive" => -1,
7881            )
7882        );
7883
7884        if ($getCorporateType && isset($getCorporateType["User"]["payment_plan_id"]) ) {
7885            $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($getCorporateType["User"]["payment_plan_id"]);
7886            $corporateLightUser = ($corporateType == Configure::read("corporate_type.light"));
7887            $corporateLimitedUser = ($corporateType == Configure::read("corporate_type.limited"));
7888        }
7889
7890        $this->set('corporateLightUser', $corporateLightUser);
7891        $this->set('corporateLimitedUser', $corporateLimitedUser);
7892        // - if reservation exceeds cancellation already
7893        $slots['show_caution_flg'] = ($this->LessonSchedule->reservationCautionFlag(array('userId' => $user_id))) ? 1 : 0;
7894        $getAvatarParams = array(
7895            "avatar_id" => $teacherId,
7896            "user_id" => $user_id,
7897            "stealth_flg" => $this->Cookie->read('stealth.setting'),
7898            'corporateLimitedUser' => $corporateLimitedUser
7899        );
7900        $avatarTeacherIds = $this->Teacher->getAvatarTeacherId($getAvatarParams);
7901        $result = $this->LessonSchedule->getAvatarSlots(array(
7902            'avatar_ids' => $avatarTeacherIds,
7903            'user_id' => $user_id,
7904            'start_day' => $start_date,
7905            'include_past' => true,
7906            'corporateLimitedUser' => $corporateLimitedUser
7907        ));
7908
7909        //campaign period start and end time
7910        $campaignPeriod = null;
7911        $checkAvatarPop = $this->userAvailPopularTeacher(
7912            array(
7913                'avatar_id' => $teacherId,
7914                'user_id' => $this->Auth->user('id'),
7915                "stealth_flg" => $this->Cookie->read('stealth.setting')
7916            )
7917        );
7918        if ($result && $checkAvatarPop) {
7919            $campaignPeriod = $this->PopularTeacherCampaignPeriod->fetchCampaignPeriod(array(
7920                'user_id' => $this->Auth->user('id'),
7921                'teacher_id' => $teacherId
7922            ));
7923        }
7924
7925        $weekday = array( __d('waiting','(日)'), __d('waiting','(月)'), __d('waiting','(火)'), __d('waiting','(水)'), __d('waiting','(木)'), __d('waiting','(金)'), __d('waiting','(土)') );
7926        $openSlots = array();
7927        $schedules = array();
7928        $tempSchedules = array();
7929
7930        if (!$result['error']) {
7931            // - get days
7932            for ($i=0; $i<=7; $i++) {
7933                $cTime = strtotime("+" . $i . " days", $userTime);
7934                $schedDate = date('m/d', $cTime);
7935                $schedules[$schedDate] = array(
7936                    'day' => $weekday[date("w", $cTime)],
7937                    'd' => date('d', $cTime),
7938                    'm' => date('m', $cTime),
7939                    'y' => date('Y', $cTime)
7940                );
7941            }
7942
7943            // - arrange open_slot
7944            foreach ($result['openSlotData'] as $slot) {
7945                $shiftTime = TimezoneTable::computeTimeToUser(array(
7946                    'time' => strtotime($slot['ShiftWorkOn']['lesson_time']),
7947                    'timestamp' => $this->timeDiffSecond
7948                ));
7949                $openSlots[date('Y-m-d H:i:s', $shiftTime)] = $slot[0]['shiftCount'];
7950                $openSlotsTemp[date('Y-m-d H:i:s', $shiftTime)] = $slot[0]['shiftCount'];
7951                $formattedLessonTime = date('Y-m-d H:i', $shiftTime);
7952                $lessonHour = date('H', $shiftTime);
7953                $lessonMinute = date('i', $shiftTime);
7954                $lessonDateTime = explode(' ', $formattedLessonTime);
7955                $lessonDate = isset($lessonDateTime[0]) ? $lessonDateTime[0] : '';
7956                $lessonDate = date('m/d', strtotime($lessonDate));
7957                $lessonTime = isset($lessonDateTime[1]) ? $lessonDateTime[1] : '';
7958
7959                // - state 7 : Available
7960                $state = 7;
7961
7962                //check before 5minutes
7963                if ((strtotime($slot['ShiftWorkOn']['lesson_time']) - strtotime($start_date)) <= 300) {
7964                    $state = 6;
7965                }
7966
7967                $schedules[$lessonDate]['slots'][$lessonTime] = array(
7968                    'open_avatar' => intval($slot[0]['shiftCount']),
7969                    'state' => $state,
7970                    'hour' => $lessonHour,
7971                    'minute' => $lessonMinute
7972                );
7973
7974                $tempSchedules[$lessonDate]['slots'][$lessonTime]['open_avatar'] = intval($slot[0]['shiftCount']);
7975
7976                if ($corporateLimitedUser && isset($slot['TeacherRankCoin'])) {
7977                    $schedules[$lessonDate]['slots'][$lessonTime]['limited_plan_reservation'] = $slot['TeacherRankCoin']['limited_plan_reservation'];
7978                }
7979            }
7980
7981
7982
7983            // - counselor ids
7984            $avatarTeacherIds = !empty($avatarTeacherIds) ? array_values($avatarTeacherIds) : array();
7985            // - counselor reservations
7986            $userSchedules = [];
7987            $otherUserSchedules = [];
7988            foreach ($result['reservationData'] as $reservation) {
7989                //get timestamp adjusted to user timezone
7990                $unixUserLessonTime = TimezoneTable::computeTimeToUser(array(
7991                    'time' => strtotime($reservation['LessonSchedule']['lesson_time']),
7992                    'timestamp' => $this->timeDiffSecond
7993                ));
7994                $timeIndex = date('Y-m-d H:i:s', $unixUserLessonTime);
7995                $formattedUserLessonTime = date('Y-m-d H:i', $unixUserLessonTime);
7996
7997                $lessonHour = date('H', $unixUserLessonTime);
7998                $lessonMinute = date('i', $unixUserLessonTime);
7999                $lessonDateTime = explode(' ', $formattedUserLessonTime);
8000                $lessonDate = isset($lessonDateTime[0]) ? $lessonDateTime[0] : '';
8001                $lessonDate = date('m/d', strtotime($lessonDate));
8002                $lessonTime = isset($lessonDateTime[1]) ? $lessonDateTime[1] : '';
8003                $lsDateTime = date('Y-m-d H:i', strtotime($reservation['LessonSchedule']['lesson_time']));
8004
8005                $tempSchedules[$lessonDate]['slots'][$lessonTime]['open_avatar'] = $openSlotsTemp[$timeIndex]--;
8006
8007                // - if another user reservation
8008                if ($reservation['LessonSchedule']['user_id'] != $user_id) {
8009                    $otherUserSchedules[$lessonDate][$lessonTime] = true;
8010                }
8011
8012                // - if my reservation
8013                if ($reservation['LessonSchedule']['user_id'] == $user_id) {
8014                    $userSchedules[$lessonDate][] = $lessonTime;
8015                    if (!in_array($reservation['LessonSchedule']['teacher_id'], $avatarTeacherIds) && !empty($openSlots[$timeIndex])) {
8016                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 2;
8017                        //get teacher details for other reservation
8018                        $teacherData = $this->LessonSchedule->getReservationData($lsDateTime, $user_id, $this->localizeDir);
8019                        $teacherData['icon_color'] = $this->LessonSchedule->getIconColor($teacherData, $lsDateTime);
8020                        $schedules[$lessonDate]['slots'][$lessonTime]['teacherData'] = $teacherData;
8021                    } elseif (!in_array($reservation['LessonSchedule']['teacher_id'], $avatarTeacherIds) && empty($openslot[$timeIndex])) {
8022                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 3;
8023                    } else {
8024                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 1;
8025                        $schedules[$lessonDate]['slots'][$lessonTime]['hour'] = $lessonHour;
8026                        $schedules[$lessonDate]['slots'][$lessonTime]['minute'] = $lessonMinute;
8027
8028                        $teacherData = $this->LessonSchedule->getReservationData($lsDateTime, $user_id, $this->localizeDir);
8029                        $teacherData['icon_color'] = $this->LessonSchedule->getIconColor($teacherData, $lsDateTime);
8030                        $schedules[$lessonDate]['slots'][$lessonTime]['ownTeacherData'] = $teacherData;
8031                    }
8032
8033                    $schedules[$lessonDate]['slots'][$lessonTime]['is_reserve'] = true;
8034                    $schedules[$lessonDate]['slots'][$lessonTime]['teacher_id'] = $reservation['LessonSchedule']['teacher_id'];
8035
8036                // - if not my reservations
8037                } elseif ((isset($schedules[$lessonDate]['slots'][$lessonTime]['state']) && $schedules[$lessonDate]['slots'][$lessonTime]['state'] != 1)) {
8038                    $openSlots[$timeIndex]--;
8039
8040                    if( isset($reservation['ShiftWorkOn']['hide_flg']) && $reservation['ShiftWorkOn']['hide_flg'] ) {
8041                        $openSlots[$timeIndex]++;
8042                    }
8043                    
8044                    # to prevent the schedule of the current user being overriden by other users schedules
8045                    if (isset($schedules[$lessonDate]['slots'][$lessonTime]['state']) && isset($schedules[$lessonDate]['slots'][$lessonTime]['is_reserve']) && $schedules[$lessonDate]['slots'][$lessonTime]['is_reserve'] ) {
8046                        continue;
8047                    }
8048
8049                    if (
8050                        (isset($disabledSchedule['disableAll']) && $disabledSchedule['disableAll'])
8051                        || (!empty($disabledSchedule['disabledDays']) && in_array(date('Y-m-d', $unixUserLessonTime), $disabledSchedule['disabledDays']))
8052                        && (!empty($openSlots[$timeIndex]) && $schedules[$formattedLessonTime]['state'] >= 5)
8053                    ) {
8054                        $openSlots[$timeIndex]--;
8055                        // - state 5 : can't reserve because of reservation limit
8056                        $schedules[$lessonDate]['slots'][$lessonTime] = array(
8057                            'state' => 5,
8058                            'hour' => $lessonHour,
8059                            'minute' => $lessonMinute,
8060                            'open_avatar' => intval($openSlots[$timeIndex])
8061                        );
8062
8063                    } elseif (!empty($openSlots[$timeIndex]) && $schedules[$lessonDate]['slots'][$lessonTime]['state'] >= 4) {
8064                        // - state 7 : Available
8065                        $schedules[$lessonDate]['slots'][$lessonTime] = array(
8066                            'state' => 7,
8067                            'hour' => $lessonHour,
8068                            'minute' => $lessonMinute,
8069                            'open_avatar' => intval($openSlots[$timeIndex])
8070                        );
8071                    } elseif (
8072                        isset($openSlots[$timeIndex])
8073                        && $openSlots[$timeIndex] <= 0
8074                        && (
8075                            isset($schedules[$formattedLessonTime]['state'])
8076                            && $schedules[$formattedLessonTime]['state'] >= 4
8077                            || empty($schedules[$formattedLessonTime]['state'])
8078                        )
8079                    ) {
8080                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 4;
8081                        $schedules[$lessonDate]['slots'][$lessonTime]['hour'] = $lessonHour;
8082                        $schedules[$lessonDate]['slots'][$lessonTime]['minute'] = $lessonMinute;
8083                        $schedules[$lessonDate]['slots'][$lessonTime]['open_avatar'] = intval($openSlots[$timeIndex]);
8084                    }
8085                }
8086            }
8087
8088            // User priority, override display schedules state
8089            foreach ($userSchedules as $lesson_date => $slots) {
8090                foreach ($slots as $lesson_time) {
8091                    // Override state when slot reserved by other
8092                    if(!empty($state = $schedules[$lesson_date]['slots'][$lesson_time]['state']) && $state === 2
8093                        && !empty($otherUserSchedules[$lesson_date][$lesson_time])) {
8094                        $schedules[$lesson_date]['slots'][$lesson_time]['state'] = 3;
8095                    }
8096                    $schedules[$lesson_date]['slots'][$lesson_time]['open_avatar'] = $tempSchedules[$lesson_date]['slots'][$lesson_time]['open_avatar'];
8097                }
8098
8099            }
8100
8101            $resData = $this->LessonSchedule->getHiddenReservation([
8102                'user_id' => $user_id
8103            ]);
8104
8105            if ($resData) {
8106                foreach ($resData as $key => $row) {
8107                    //get timestamp adjusted to user timezone
8108                    $unixUserLessonTime = TimezoneTable::computeTimeToUser(array(
8109                        'time' => strtotime($key),
8110                        'timestamp' => $this->timeDiffSecond
8111                    ));
8112                    $timeIndex = date('Y-m-d H:i:s', $unixUserLessonTime);
8113                    $lessonDate = date('m/d', $unixUserLessonTime);
8114                    $lessonTime = date('H:i', $unixUserLessonTime);
8115
8116                    if (
8117                        !empty($openSlots[$timeIndex]) && 
8118                        !isset($schedules[$lessonDate]['slots'][$lessonTime]['teacherData']) &&
8119                        !isset($schedules[$lessonDate]['slots'][$lessonTime]['ownTeacherData'])
8120                    ) {
8121
8122                        $lessonRequestSlotData = $this->LessonSchedule->getReservationData($key, $user_id, $this->localizeDir);
8123                        if (!empty($lessonRequestSlotData)) {
8124                            $lessonRequestSlotData['icon_color']  = $this->LessonSchedule->getIconColor($lessonRequestSlotData, $key);
8125
8126                            if (in_array($lessonRequestSlotData['teacher_id'], $avatarTeacherIds) && $lessonRequestSlotData['reservation_status'] == Configure::read('lesson_schedule.status.on_reserve')) {
8127                                $schedules[$lessonDate]['slots'][$lessonTime]['ownTeacherData'] = $lessonRequestSlotData;
8128                                $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 1;
8129                            } else {
8130                                $schedules[$lessonDate]['slots'][$lessonTime]['teacherData'] = $lessonRequestSlotData;
8131                                $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 2;
8132                            }
8133                        }
8134                    }
8135                }
8136            } 
8137
8138            if ($ifForCancellation) {
8139                $this->autoRender = false;
8140                return json_encode($schedules);
8141            }
8142            
8143            // NJ-33414
8144            $this->UsersDetail->openDBReplica();
8145            $fetchUsersDetail = $this->UsersDetail->find('first', array(
8146                'fields' => array(
8147                    'lesson_request_flg'
8148                ),
8149                'conditions' =>  array('user_id' => $this->sharedUserData['User']['id']),
8150                'recursive' => -1
8151            ));
8152            $this->UsersDetail->closeDBReplica();
8153            
8154            $times = array();
8155            $utcMin = explode(':', $this->utcOffset);
8156            if ($utcMin[1] == "45") {
8157                for ($i=0; $i<=23; $i++) {
8158                    $times[] = sprintf("%02d",$i) . ':15';
8159                    $times[] = sprintf("%02d",$i) . ':45';
8160                }
8161            } else {
8162                for ($i=0; $i<=23; $i++) {
8163                    $times[] = sprintf("%02d",$i) . ':00';
8164                    $times[] = sprintf("%02d",$i) . ':30';
8165                }
8166            }
8167            $this->set('times', $times);
8168            $this->set('teacherId', $teacherId);
8169            $this->set('schedules', $schedules);
8170            $this->set('campaignPeriod', $campaignPeriod);
8171        }
8172    }
8173
8174    /**
8175     * @api {post} /user/waiting/counselingLimit counselingLimit()
8176     * @apiName counselingLimit
8177     * @apiGroup Waiting
8178     * @apiDescription Checks the reservation and cancellation limits for counseling sessions for the authenticated user in Native Camp. It returns the status and any relevant messages or limits.
8179     *
8180     * @apiBody {String} action The action to perform (add or cancel).
8181     * @apiBody {String} [lessonDate] The date of the lesson (required for add action).
8182     * @apiBody {String} [lessonTime] The time of the lesson (required for cancel action).
8183     * 
8184     * @apiSuccess {String} status The status of the request (OK or NG).
8185     * @apiSuccess {Number} content The content of the response (0: No issues, 1: Caution flag, 2: Exceeds total reservation limit, 3: Exceeds counselor reservations per day limit, 4: Exceeds cancellation limit, 5: Beyond available days for complimentary plan, 6: Exceeds corporate light lesson limit, 7: Cancel in time not allowed).
8186     * @apiSuccess {Object} lastDetails The last counseling details.
8187     * @apiSuccess {Number} lastDetails.id The ID of the last counseling session.
8188     * @apiSuccess {String} lastDetails.lesson_time The time of the last counseling session.
8189     * @apiSuccess {Number} lastDetails.teacher_id The ID of the teacher for the last counseling session.
8190     * @apiSuccess {Number} lastDetails.user_id The ID of the user for the last counseling session.
8191     * @apiSuccess {Number} cancelCount The count of cancellations by the user.
8192     * @apiSuccess {Number} displayNotice Indicates whether to display a notice (0: No, 1: Yes).
8193     * @apiSuccess {String} nextChargeDate The next charge date for the user.
8194     * @apiSuccess {Boolean} isExpired Indicates whether the user's coin has expired.
8195     * 
8196     * @apiSuccessExample {json} Success-Response:
8197     *     {
8198     *         "status": "OK",
8199     *         "content": 0,
8200     *         "lastDetails": {
8201     *             "id": 123456,
8202     *             "lesson_time": "2023-12-01 12:00:00",
8203     *             "teacher_id": 123,
8204     *             "user_id": 123
8205     *         },
8206     *         "cancelCount": 1,
8207     *         "displayNotice": 0,
8208     *         "nextChargeDate": "2023年12月01日",
8209     *         "isExpired": false
8210     *     }
8211     *
8212     * @apiError {String} status The status of the request (NG).
8213     * @apiError {Number} content The content of the response (0: No issues).
8214     * @apiError {Number} cancelCount The count of cancellations by the user.
8215     * @apiError {Number} displayNotice Indicates whether to display a notice (0: No, 1: Yes).
8216     *
8217     * @apiErrorExample {json} Error-Response:
8218     *     {
8219     *         "status": "NG",
8220     *         "content": 0,
8221     *         "cancelCount": 0,
8222     *         "displayNotice": 0
8223     *     }
8224     * 
8225     * @apiSampleRequest off
8226     */
8227    public function counselingLimit() {
8228        $this->autoRender = false;
8229        if ($this->request->is('ajax')) {
8230
8231            $userCancelledReservation = 0;
8232            $userId = $this->Auth->user('id');
8233            $action = $this->request->data['action'];
8234            $content = 0;
8235            if ($action == 'add') {
8236
8237                if (empty($this->request->data['lessonDate'])) {
8238                    return json_encode(array(
8239                        'status' => 'NG',
8240                        'content' => 0
8241                    ));
8242                }
8243
8244                // if complimentary user plan
8245                $user = $this->sharedUserData['User'];
8246                if (isset($user['payment_plan_id']) && $user['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')) {
8247                    $this->loadModel('ComplimentaryCode');
8248                    $user['lessonTime'] = date('Y-m-d', strtotime($this->request->data['lessonDate']));
8249                    if (!$result = $this->ComplimentaryCode->validateUserComplimentaryPlan($user)) {
8250                        // set beyond available days to true
8251                        return json_encode(array('status' => 'OK', 'content' => 5));
8252                    }
8253                }
8254
8255                $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($user['payment_plan_id']);
8256
8257                // NC-7361 - corporate light
8258                if (isset($corporateType) && $corporateType == Configure::read('corporate_type.light')) {
8259                    if (ClassRegistry::init('Corporate')->corpLightLessonMaxLimit(array("user_id" => $userId))) {
8260                        return json_encode(array('status' => 'OK', 'content' => 6));
8261                    }
8262                }
8263
8264                // - get total reservation
8265                $totalReservation = $this->LessonSchedule->countUserTotalReservation(array('userId' => $userId));
8266
8267                // - check if total reservation exceeds limit
8268                if ($totalReservation >= Configure::read("maximum_number_of_total_reservation")) {
8269                    $content = 2;
8270                } else {
8271                    // - show caution flag
8272                    $reservationCautionFlag = $this->LessonSchedule->reservationCautionFlag(array(
8273                        'userId' => $userId,
8274                        'timestamp' => $this->timeDiffSecond
8275                    ));
8276
8277                    // - check reservation limit 4reservations/day
8278                    $totalReservationCounselor = $this->LessonSchedule->countUserReservationForTeacherCounselor(array(
8279                        'userId' => $userId,
8280                        'lessonDate' => $this->request->data['lessonDate'],
8281                        'timeDiffSecond' => $this->timeDiffSecond
8282                    ));
8283
8284                    // - check counselor reservations per day limit
8285                    if ($totalReservationCounselor >= 4) {
8286                        $content = 3;
8287
8288                    // - check caution flag and not yet over 20 max limit total reservation
8289                    } elseif ($reservationCautionFlag && $totalReservation < 20) {
8290                        $content = 1;
8291                    }
8292                }
8293
8294            } else {
8295                // - count total cancellations
8296                $userCancelledReservation = $this->LessonScheduleCancel->countCancelledReservation(array('userId' => $userId));
8297                if ($userCancelledReservation >= 3) {
8298                    $content = 4;
8299                }
8300
8301                // cancel in time not allowed
8302                if(!empty($this->request->data['lessonTime']) && !$content){
8303
8304                    // if time >= lesson time(server time)
8305                    if(strtotime('now') >= strtotime($this->request->data['lessonTime'])){
8306                        $content = 7;
8307                    }
8308                }
8309            }
8310            // get user counseling attended flag status
8311            $userData = $this->User->getUserData(
8312                array('User.id' => $userId),
8313                array(
8314                    'User.counseling_attended_flg',
8315                    'User.next_charge_date'
8316                ),
8317                'first'
8318            );
8319
8320            $nextChargeDate = "";
8321            if (isset($userData['User']['next_charge_date'])) {
8322                $chargeDateJP = TimezoneTable::computeTimeToUser(array(
8323                    'time' => strtotime($userData['User']['next_charge_date']),
8324                    'timestamp' => $this->timeDiffSecond
8325                ));
8326                $nextChargeDate = date('Y', $chargeDateJP) . "年" . date('m', $chargeDateJP) . "月" . date('d', $chargeDateJP) . "日";
8327            }
8328            //This will be get last records for counselor details
8329            $getLastDetails = $this->Counseling->getLastCounselingById($userId);
8330
8331            $params23 = array(
8332                'user_id' => $userId,
8333                'lesson_time' =>  $this->request->data['lessonTime']
8334            );
8335            $lsId = $this->LessonSchedule->counselorCheckExpiredCoin($params23);
8336
8337            // NC-8428 - check if user has user point history record
8338            $_lsId = isset($lsId['LessonSchedule']['id']) ? $lsId['LessonSchedule']['id'] : null;
8339            $pointParam = array(
8340                'log_id' => $_lsId,
8341                'user_id' => $userId,
8342                'kbn_type' => 2, // coin  use
8343                'expiration_flg' => 2,
8344                'payment_plan_id' => isset($this->sharedUserData['User']['payment_plan_id']) ? $this->sharedUserData['User']['payment_plan_id'] : null
8345            );
8346            $isExpired = ClassRegistry::init('UsersPointHistory')->checkCoinExpiration($pointParam);
8347
8348            return json_encode(array(
8349                'status' => 'OK',
8350                'content' => $content,
8351                'lastDetails' => $getLastDetails,
8352                'cancelCount' => $userCancelledReservation,
8353                'displayNotice' => (isset($userData['User']['counseling_attended_flg'])) ? $userData['User']['counseling_attended_flg'] : 0,
8354                'nextChargeDate' => $nextChargeDate,
8355                'isExpired' => $isExpired,
8356            ));
8357        } else {
8358            return json_encode(array(
8359                'status' => 'NG',
8360                'content' => 0,
8361                'cancelCount' => 0,
8362                'displayNotice' => 0
8363            ));
8364        }
8365    }
8366
8367    /**
8368     * @api {post} /user/waiting/avatarLimit avatarLimit()
8369     * @apiName avatarLimit
8370     * @apiGroup Waiting
8371     * @apiDescription Checks the reservation and cancellation limits for avatar lessons for the authenticated user in Native Camp. It returns the status and any relevant messages or limits.
8372     *
8373     * @apiBody {String} action The action to perform (add or cancel).
8374     * @apiBody {String} teacher_avatar The ID of the avatar teacher.
8375     * @apiBody {String} [lessonDate] The date of the lesson (required for add action).
8376     * @apiBody {String} [lessonTime] The time of the lesson (required for cancel action).
8377     * 
8378     * @apiSuccess {String} status The status of the request (OK or NG).
8379     * @apiSuccess {Number} content The content of the response (0: No issues, 1: Caution flag, 2: Exceeds total reservation limit, 3: Exceeds avatar reservations per day limit, 4: Exceeds cancellation limit, 5: Beyond available days for complimentary plan, 6: Exceeds corporate light lesson limit, 7: Cancel in time not allowed).
8380     * @apiSuccess {Number} cancelCount The count of cancellations by the user.
8381     * @apiSuccess {Number} displayNotice Indicates whether to display a notice (0: No, 1: Yes).
8382     * @apiSuccess {String} nextChargeDate The next charge date for the user.
8383     *
8384     * @apiSuccessExample {json} Success-Response:
8385     *     {
8386     *         "status": "OK",
8387     *         "content": 0,
8388     *         "cancelCount": 1,
8389     *         "displayNotice": 0,
8390     *         "nextChargeDate": "2023年12月01日"
8391     *     }
8392     *
8393     * @apiError {String} status The status of the request (NG).
8394     * @apiError {Number} content The content of the response (0: No issues).
8395     * @apiError {Number} cancelCount The count of cancellations by the user.
8396     * @apiError {Number} displayNotice Indicates whether to display a notice (0: No, 1: Yes).
8397     *
8398     * @apiErrorExample {json} Error-Response:
8399     *     {
8400     *         "status": "NG",
8401     *         "content": 0,
8402     *         "cancelCount": 0,
8403     *         "displayNotice": 0
8404     *     }
8405     * 
8406     * @apiSampleRequest off
8407     */
8408    public function avatarLimit() {
8409        $this->autoRender = false;
8410        if ($this->request->is('ajax')) {
8411
8412            $userCancelledReservation = 0;
8413            $userId = $this->Auth->user('id');
8414            $action = $this->request->data['action'];
8415            $teacherAvatarId = $this->request->data['teacher_avatar'];
8416            $content = 0;
8417            if ($action == 'add') {
8418
8419                if (empty($this->request->data['lessonDate'])) {
8420                    return json_encode(array(
8421                        'status' => 'NG',
8422                        'content' => 0
8423                    ));
8424                }
8425
8426                // if complimentary user plan
8427                $user = $this->sharedUserData['User'];
8428                if (isset($user['payment_plan_id']) && $user['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')) {
8429                    $this->loadModel('ComplimentaryCode');
8430                    $user['lessonTime'] = date('Y-m-d', strtotime($this->request->data['lessonDate']));
8431                    if (!$result = $this->ComplimentaryCode->validateUserComplimentaryPlan($user)) {
8432                        // set beyond available days to true
8433                        return json_encode(array('status' => 'OK', 'content' => 5));
8434                    }
8435                }
8436
8437                $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($user['payment_plan_id']);
8438
8439                // NC-7361 - corporate light
8440                if (isset($corporateType) && $corporateType == Configure::read('corporate_type.light')) {
8441                    if (ClassRegistry::init('Corporate')->corpLightLessonMaxLimit(array("user_id" => $userId))) {
8442                        return json_encode(array('status' => 'OK', 'content' => 6));
8443                    }
8444                }
8445
8446                // - get total reservation
8447                $totalReservation = $this->LessonSchedule->countUserTotalReservation(array('userId' => $userId));
8448
8449                // - check if total reservation exceeds limit
8450                if ($totalReservation >= Configure::read("maximum_number_of_total_reservation")) {
8451                    $content = 2;
8452                } else {
8453                    // - show caution flag
8454                    $reservationCautionFlag = $this->LessonSchedule->reservationCautionFlag(array(
8455                        'userId' => $userId,
8456                        'timestamp' => $this->timeDiffSecond
8457                    ));
8458
8459                    // - check reservation limit 4reservations/day
8460                    $totalReservationAvatar = $this->LessonSchedule->countUserReservationForTeacherAvatar(array(
8461                        'avatar_id' => $teacherAvatarId,
8462                        'userId' => $userId,
8463                        'lessonDate' => $this->request->data['lessonDate'],
8464                        'timeDiffSecond' => $this->timeDiffSecond
8465                    ));
8466
8467                    // - check avatar reservations per day limit
8468                    if ($totalReservationAvatar >= 4) {
8469                        $content = 3;
8470
8471                    // - check caution flag and not yet over 20 max limit total reservation
8472                    } elseif ($reservationCautionFlag && $totalReservation < 20) {
8473                        $content = 1;
8474                    }
8475                }
8476
8477            } else {
8478                // - count total cancellations
8479                $userCancelledReservation = $this->LessonScheduleCancel->countCancelledReservation(array('userId' => $userId));
8480                if ($userCancelledReservation >= 3) {
8481                    $content = 4;
8482                }
8483
8484                // cancel in time not allowed
8485                if(!empty($this->request->data['lessonTime']) && !$content){
8486
8487                    // if time >= lesson time(server time)
8488                    if(strtotime('now') >= strtotime($this->request->data['lessonTime'])){
8489                        $content = 7;
8490                    }
8491                }
8492            }
8493            // get user
8494            $userData = $this->User->getUserData(
8495                array('User.id' => $userId),
8496                array(
8497                    'User.next_charge_date'
8498                ),
8499                'first'
8500            );
8501
8502            $nextChargeDate = "";
8503            if (isset($userData['User']['next_charge_date'])) {
8504                $chargeDateJP = TimezoneTable::computeTimeToUser(array(
8505                    'time' => strtotime($userData['User']['next_charge_date']),
8506                    'timestamp' => $this->timeDiffSecond
8507                ));
8508                $nextChargeDate = date('Y', $chargeDateJP) . "年" . date('m', $chargeDateJP) . "月" . date('d', $chargeDateJP) . "日";
8509            }
8510
8511            return json_encode(array(
8512                'status' => 'OK',
8513                'content' => $content,
8514                'cancelCount' => $userCancelledReservation,
8515                'displayNotice' => 0,
8516                'nextChargeDate' => $nextChargeDate
8517            ));
8518        } else {
8519            return json_encode(array(
8520                'status' => 'NG',
8521                'content' => 0,
8522                'cancelCount' => 0,
8523                'displayNotice' => 0
8524            ));
8525        }
8526    }
8527
8528    /**
8529     * @api {post} /user/waiting/checkCounselingReservationNow checkCounselingReservationNow()
8530     * @apiName checkCounselingReservationNow
8531     * @apiGroup Waiting
8532     * @apiDescription Checks if the user has a reserved counseling session at the current time. It returns the status of the reservation and the teacher's information if available.
8533     *
8534     * @apiBody {String} userId The ID of the user.
8535     * 
8536     * @apiSuccess {String} status The status of the request (OK or NG).
8537     * @apiSuccess {Number} [state] The state of the counseling reservation (1: No reserved counseling, 2: Reserved counseling and teacher is on standby, 3: Reserved counseling and teacher is not on standby).
8538     * @apiSuccess {String} [teacher_id] The ID of the teacher (if state is 2).
8539     * @apiSuccess {String} [chat_hash] The chat hash of the lesson (if state is 2).
8540     *
8541     * @apiSuccessExample {json} Success-Response:
8542     *     {
8543     *         "status": "OK",
8544     *         "state": 2,
8545     *         "teacher_id": "123",
8546     *         "chat_hash": "example_chat_hash"
8547     *     }
8548     *
8549     * @apiError {String} status The status of the request (NG).
8550     *
8551     * @apiErrorExample {json} Error-Response:
8552     *     {
8553     *         "status": "NG"
8554     *     }
8555     * 
8556     * @apiSampleRequest off
8557     */
8558    public function checkCounselingReservationNow() {
8559        $this->autoRender = false;
8560        $data = $this->request->data;
8561        $result = array('status' => 'OK');
8562
8563        if (empty($data['userId'])) {
8564            return json_encode(array(
8565                'status' => 'NG'
8566            ));
8567        }
8568
8569        if ($this->request->is('ajax')) {
8570            //target lesson schedule start time
8571            $minutes = date('i');
8572            if ($minutes >= 0 && $minutes < 26) {
8573                $lessonTime = date('Y-m-d H:00:00');
8574            } elseif ($minutes >= 30 && $minutes < 56) {
8575                $lessonTime = date('Y-m-d H:30:00');
8576            } else {
8577                // - [1] if user has no reserved counseling
8578                $result['state'] = 1;
8579                return json_encode($result);
8580            }
8581
8582            // - check ongoing lesson
8583            $counselingInfo = $this->LessonSchedule->find('first', array(
8584                    'fields' => array(
8585                        'LessonSchedule.id',
8586                        'LessonOnair.teacher_id',
8587                        'LessonOnair.chat_hash'
8588                    ),
8589                    'conditions' => array(
8590                        'LessonSchedule.lesson_time' => $lessonTime,
8591                        'LessonSchedule.user_id' => $data['userId']
8592                    ),
8593                    'joins' => array(
8594                        array(
8595                            'type' => 'LEFT',
8596                            'table' => 'lesson_onairs',
8597                            'alias' => 'LessonOnair',
8598                            'conditions' => array('LessonSchedule.teacher_id = LessonOnair.teacher_id AND LessonOnair.connect_flg = 1')
8599                        ),
8600                        array(
8601                            'type' => 'INNER',
8602                            'table' => 'teachers',
8603                            'alias' => 'Teacher',
8604                            'conditions' => array('Teacher.id = LessonOnair.teacher_id AND Teacher.counseling_flg = 1')
8605                        )
8606                    ),
8607                    'recursive' => -1
8608                )
8609            );
8610
8611            // - [1] if user has no reserved counseling
8612            if (empty($counselingInfo)) {
8613                $result['state'] = 1;
8614                return json_encode($result);
8615            }
8616
8617            // - [2] if user has reserved counseling and teacher is on standby
8618            if (!empty($counselingInfo['LessonOnair']['chat_hash'])) {
8619                $result['state'] = 2;
8620                $result['teacher_id'] = $counselingInfo['LessonOnair']['teacher_id'];
8621                $result['chat_hash'] = $counselingInfo['LessonOnair']['chat_hash'];
8622                return json_encode($result);
8623
8624            // - [3] if user has reserved counseling and teacher is not on standby
8625            } elseif (empty($counselingInfo['LessonOnair']['chat_hash'])) {
8626                $result['state'] = 3;
8627                return json_encode($result);
8628            } else {
8629                $result['state'] = 1;
8630                return json_encode($result);
8631            }
8632
8633        } else {
8634            return json_encode(array(
8635                'status' => 'NG'
8636            ));
8637        }
8638    }
8639
8640
8641    //Retrieves the details of a specific teacher for the mobile view in Native Camp. It returns various information about the teacher, including lesson history, reviews, and more.
8642    public function spDetail($teacherId) {
8643        if (!intval($teacherId)) {
8644            return $this->redirect(myTools::getUrl() . '/user/mobapp/retrypage');
8645        }
8646
8647        // NJ-10759: redirect to mypage if teacher detail sp is counseling and access from teacher mobapp
8648        // redirect if counseling teacher
8649        $counselorParams = array(
8650            'type' => 'count',
8651            'args' => array(
8652                'conditions' => array(
8653                    'id' => $teacherId,
8654                    'counseling_flg' => 1
8655                ),
8656                'recursive' => -1
8657            )
8658        );
8659
8660
8661        // - NC-3802: redirect to mypage if counselor teacher
8662        if ($this->Teacher->getTeachers($counselorParams)) {
8663            return $this->redirect(myTools::getUrl() . '/user/mypage');
8664        }
8665
8666        //fetch teacher data
8667        $data = $this->Teacher->findById($teacherId);
8668
8669        //no teacher data
8670        if (!$data) {
8671            return $this->redirect(myTools::getUrl() . '/user/mobapp/retrypage');
8672        }
8673
8674        // //check company ip and if the teacher is stealth on redirect to teacher list
8675        // if (!myTools::checkCompanyIP($_SERVER['REMOTE_ADDR']) && $data['Teacher']['stealth_flg']) {
8676        //     return $this->redirect(array('controller' => 'SpTeacher', 'action' => 'index'));
8677        // }
8678
8679        //redirect if withdrawn teacher
8680        if ($data['Teacher']['status'] <> 1  || $data['Teacher']['inactive_flg'] == 1) {
8681            return $this->redirect(myTools::geturl() . '/waiting');
8682        }
8683
8684        if(in_array($data['Teacher']['rank_coin_id'], $this->blockMemberSettings)) {
8685            return $this->redirect('/waiting');
8686        }
8687
8688        // - check if blocked student
8689        if (BlockListTable::isUserBlocked($this->Auth->User('id'), $teacherId) == true) {
8690            return $this->redirect('/waiting');
8691        }
8692
8693        // - NC-7031: redirect avatar
8694        $avatarData = $this->isAvatar($teacherId);
8695
8696        if ($avatarData) {
8697            $getAId = $avatarData;
8698            return $this->redirect('/avatar_detail/'.$getAId);
8699        }
8700
8701        //lesson onair
8702        $onair1 = $this->LessonOnair->find('first', array(
8703            'fields' => array('LessonOnair.status', 'LessonOnair.connect_flg'),
8704            'conditions' => array('LessonOnair.teacher_id' => $data['Teacher']['id'])
8705        ));
8706
8707        //teacher_status if login or break
8708        $teacherStatus1 = $this->TeacherStatus->find('first', array(
8709            'fields' => array('TeacherStatus.status', 'TeacherStatus.remarks1'),
8710            'conditions' => array('TeacherStatus.teacher_id' => $data['Teacher']['id']))
8711            );
8712        // get counrty details
8713        $teacherCountryDetails = $this->CountryCode->find('first', array(
8714            'fields' => array('country_name', 'nationality', 'code'),
8715            'conditions' => array('CountryCode.id' => $data['Teacher']['homeland2']))
8716            );
8717
8718        //get own reviews
8719        $selfReviews = array();
8720        $selfLessonCount = 0;
8721        $selfLessonNow = 0;
8722        $selfReservation = 0;
8723        $daysPast = 0;
8724        $userId = $this->Auth->user('id');
8725        $this->set('userId', $userId);
8726        if ($userId) {
8727            $this->set('user_lang',  $this->sharedUserData['User']['native_language2']);
8728            $selfReviews = $this->getUserReviews($userId, $teacherId);
8729            $userLessonDetail = $this->LessonOnairsLog->getUserLessonCount($userId, $teacherId);
8730            $selfLessonNow = $userLessonDetail['lessonCount'];
8731            $selfReservation = $userLessonDetail['reserveCount'];
8732            $selfLessonCount = $selfLessonNow + $selfReservation;
8733            $daysPast = $this->LessonOnairsLog->countDaysPast($userId, $teacherId);
8734        }
8735
8736        if (!empty($onair1)) {
8737            $onair = new LessonOnairTable($onair1['LessonOnair']);
8738        } elseif (!empty($teacherStatus1)) {
8739            $onair = new TeacherStatusTable($teacherStatus1['TeacherStatus']);
8740        } else {
8741            $onair = 0;
8742        }
8743
8744        $rateBreakdown = null;
8745        $rating = $this->UsersClassEvaluation->getRatings($teacherId, true);
8746        if ($rating) {
8747            $rates = new UsersClassEvaluationTable($rating['UsersClassEvaluation']);
8748            $rateBreakdown = new UsersClassEvaluationTable($rating['TeacherWeeklyRating']);
8749        }
8750
8751        $this->set('onair', $onair);
8752        $this->set('teacher_id', $teacherId);
8753
8754        $teacher = new TeacherTable($data['Teacher']);
8755        $country = new TeacherTable($teacherCountryDetails['CountryCode']);
8756        $tutorCategory = new TeacherRankCoinTable($data['TeacherRankCoin']);
8757        $meta_desc = preg_replace('/\s+/', ' ', trim($teacher->getMetaMobile()));
8758        $this->set('teacher', $teacher);
8759
8760        # get weekly rating
8761        $get_weekly_rating = $this->UsersClassEvaluation->getRatings($teacherId,true);
8762        if ($get_weekly_rating['TeacherWeeklyRating']['averageRate']) {
8763            $get_weekly_rating['TeacherWeeklyRating']['ratings'] = $get_weekly_rating['TeacherWeeklyRating']['averageRate'];
8764        }
8765
8766        //number of lesson
8767        $lessonCount = (int)$teacher->lesson_count;
8768
8769        // Translate and save translated data
8770        $globalTranslate = TeacherTable::translate(array(
8771            'id' => $teacher->id,
8772            'lang'=> isset($this->localizeDir) ? $this->localizeDir : $this->lang_iso,
8773            'controller' => static::class
8774        ));
8775        $translatedMessageTranslation = isset($globalTranslate['message']) ? $globalTranslate['message'] : null;
8776        $translatedThirdppTranslation = isset($globalTranslate['self_introduction_third_pp']) ? $globalTranslate['self_introduction_third_pp'] : null;
8777        $this->set('message', $translatedMessageTranslation);
8778        $this->set('intro', $translatedThirdppTranslation);
8779
8780        // NJ-32759
8781        $userLang = isset($this->localizeDir) ? $this->localizeDir : Configure::read('english_language_id');
8782        $languageIds = $this->CountryCode->getLanguageList(['field'=>'iso_639_1']);
8783        $getCRData = $this->Teacher->getCountryResidenceData($teacherId, $userLang, 'first', $languageIds);
8784        $residenceData = $this->getResidenceData($getCRData);
8785        $this->set('residenceData',$residenceData);
8786        $this->set('residenceFlg',$residenceData['countryFlag']);
8787
8788        // get teacher strength feature items
8789        $strengthItemsParams = array(
8790            'teacherId' => $teacherId,
8791            'type' => 0,
8792            'langId' => $this->CountryCode->getUserLanguageId($this->localizeDir),
8793            'limit' => 3
8794        );
8795        $showRating = $teacher->getReviewOption($teacher->rank_coin_id);
8796        $this->set('showRating', $showRating);
8797        $strengthItems = $this->TeacherFeatureRating->getFeatureRatingItems($strengthItemsParams);
8798        $this->set('strengthItems', $strengthItems);
8799        
8800        // - prepare head text
8801        $headTextWD = $pageTitleWD = $teacher->name;
8802        $metaDescWD = "";
8803        if ($this->localizeDir == Configure::read('default.user_language')) {
8804            $headTextWD .= '('.$teacher->jp_name.')';
8805            $pageTitleWD .=  '('.$teacher->jp_name.')';
8806            //$metaDescWD .= '('.$teacher->jp_name.')';
8807        }
8808
8809        //find the selfintro 
8810        $TeacherTable = new TeacherTable($teacher);
8811        $_userSelfIntro = $TeacherTable->iSNotDisplayHtmlTags($teacher->message);
8812        $_userSelfIntro = strip_tags($_userSelfIntro); 
8813
8814        //prepare meta image 
8815        $_teacherImgUrl = $teacher->getImageUrl();
8816
8817        //check if teacher has no image 
8818        if (empty($teacher->image_url) || !$teacher->image_url) {
8819            $defaultTeacherImg = myTools::getUrl() . '/teacher/img/no_profile_img.jpg';
8820            $_teacherImgUrl = ($_teacherImgUrl == $defaultTeacherImg) ? $_teacherImgUrl : $defaultTeacherImg;
8821        }
8822
8823        $headTextWD .= '&ensp;' . __d('waiting', 'レッスン').':'.$lessonCount.__d('waiting', '回');
8824        $pageTitleWD .= '&ensp;' . sprintf(__d('waiting', 'レッスン:%s回 - 講師詳細 | オンライン英会話のネイティブキャンプ'), $lessonCount);
8825        //$metaDescWD .= '講師の紹介ページです。'.$teacher->getMetaDescription();
8826        $metaDescWD = TeacherTable::getMetaDescription2($_userSelfIntro);
8827
8828
8829        // NJ-3786 textbook teacher recommendation
8830        $curDate = date('Y-m-d');
8831        $userId = $this->Auth->user('id') ? $this->Auth->user('id') : null;
8832        $txtTeacherRecommendlimit = 10;
8833        $userData = isset($this->sharedUserData['User']) && $this->sharedUserData['User'] ? $this->sharedUserData['User'] : null;
8834        $endDate = date('Y-m-d',strtotime('-1 day' ,strtotime($curDate)));
8835        $beginDate = date('Y-m-d',strtotime('-1 month' ,strtotime($curDate)));
8836
8837        if( $userId ) {
8838            $teacherObj = new TeacherTable($data['Teacher']);
8839            $lastBookUsedData = $this->UsersTextbookInfo->getCurrentTextbookAndBadgeData( array( 'user_id' => $userId ) );
8840            $textbookCategoryId = $lastBookUsedData['category_id'];
8841            $textbookBadge = $lastBookUsedData['textbook_badge'];
8842            $paramsArr = array(
8843                'user_id' => $userId,
8844                'begin_date' => $beginDate,
8845                'end_date' => $endDate,
8846                'textbook_category' => $textbookCategoryId,
8847                'textbook_badge' => $textbookBadge,
8848                'limit' => $txtTeacherRecommendlimit,
8849                'user_data' => $userData,
8850                'exclude_teacher_id' => $teacherId
8851            );
8852
8853            $teacherTextbookStatData = $this->TeacherTextbookStat->fetchTextbookTeacherRatingData($paramsArr);
8854            if( $teacherTextbookStatData ) {
8855                $dataList = $this->arrangeTeacherRecommendList( array( 
8856                        'user_id' => $userId,
8857                        'data' => $teacherTextbookStatData,
8858                        'category_id' => $textbookCategoryId,
8859                        'user_data' => $userData
8860                    ) 
8861                );
8862                $this->set('textbookTeacherData', $dataList);
8863            }
8864
8865            // - user callan unli option flg
8866            $callan_option = isset($this->sharedUserData['User']['callan_option']) ? $this->sharedUserData['User']['callan_option'] : 0;
8867
8868            // - user native unli option flg
8869            $native_option = isset($this->sharedUserData['User']['native_option']) ? $this->sharedUserData['User']['native_option'] : 0;
8870
8871            $can_use_callan_option = 0;
8872            if($callan_option || $native_option) {
8873                $can_use_callan_option = 1;
8874            }
8875
8876            $this->set('can_use_callan_option', $can_use_callan_option);
8877
8878            // - teacher callan unli option flg
8879            $unlimited_option_flag = $this->HomeBasedRankBasicAmount->getUnlimitedOptionFlg($teacherObj->current_rank_id);
8880            $callan_option_teacher_flg = (isset($unlimited_option_flag['callan_unlimited_option_flg']) && $unlimited_option_flag['callan_unlimited_option_flg']) ? $unlimited_option_flag['callan_unlimited_option_flg'] : 0; 
8881            $this->set('callan_option_teacher_flg', $callan_option_teacher_flg);
8882            
8883            // - check if has callan badge
8884            $teacher_callan_badge = ClassRegistry::init('TeacherBadge')->checkCallanBadges(array('teacher_id' => $teacherId));
8885            $this->set('teacher_callan_badge', $teacher_callan_badge);
8886        }
8887
8888        // - set page meta information
8889        $this->set('headtext', $headTextWD);
8890        $this->set('title_for_layout', $pageTitleWD);
8891        $this->set('meta_description', $metaDescWD);
8892        $this->set('lessonCount', $lessonCount);
8893        $this->set('country', $country);
8894        $this->set('rateBreakdown', $rateBreakdown);
8895        $this->set('selfReviews', $selfReviews);
8896        $this->set('selfLessonCount', $selfLessonCount);
8897        $this->set('daysPast', $daysPast);
8898        $this->set('meta_teacher_img',$_teacherImgUrl);
8899
8900        # get studydapuri textbooks
8901        $studysapuriType = Configure::read('studysapuri_textbook_category_types');
8902        if ( $this->studySapuriId && isset($this->sharedUserData['User']['payment_plan_id']) ) {
8903            $plan = myTools::studySapuriContractPlan($this->sharedUserData['User']['payment_plan_id']);
8904            $conArr['TextbookCategory.textbook_category_type'] = $studysapuriType[$plan];
8905        } elseif ($this->isStudySapuriTosUser) {
8906            $conArr['TextbookCategory.textbook_category_type'] = Configure::read('stasapu_tos_textbook_category_type');
8907        } else {
8908            $exCat = Configure::read('all_sapuri_textbook_category_types');
8909            $conArr['NOT'] = array('TextbookCategory.textbook_category_type' => $exCat);
8910        }
8911
8912        $return = TeacherDetailTable::teacherIntroDetails($data, $this->localizeDir,$this->Auth->loggedIn(),$conArr);
8913
8914        [$historyYear, $historyMonth] = $teacher->getTotalTeachingExperience();
8915        $teacherOccupation = ClassRegistry::init('TeacherOccupationDetail')->getTeacherOccupationDetails($teacherId);
8916        $reserveAndCancel = $this->getReserveAndCancelled($teacherId);
8917        $lessonHistories = $this->getLessonHistory(true, $teacherId);
8918        $favoriteCount = $this->UsersFavorite->find('count', array('conditions' => array('UsersFavorite.teacher_id' => $teacherId)));
8919
8920        $teacherCurrentRankId = ClassRegistry::init('Teacher')->getTeacherCurrentRankId($teacherId);
8921        $coinParams =  array(
8922            'current_rank_id' => $teacherCurrentRankId,
8923            'reserve_coin_data_id' => $teacher->reserve_coin_data_id,
8924            'reserve_coin_settings_flg' => $tutorCategory->reserve_coin_settings_flg,
8925            'student_native_option' => $userData->native_option,
8926            'home_flg' => $teacher->home_flg,
8927            'counseling_flg' => $teacher->counseling_flg,
8928            'avatar_parent_flg' => $teacher->avatar_parent_flg,
8929            'avatar_flg' => $teacher->avatar_flg,
8930            'native_speaker_flg' => $teacher->native_speaker_flg
8931        );
8932
8933        // get teacher coin settings
8934        $teacherReserveCoin = $this->Teacher->getTeacherReserveCoin($coinParams);
8935        $teacherCoinData = [];
8936        if($teacherReserveCoin){
8937            // set teacher reservation coin
8938            $teacherCoinData = [
8939                'lesson_now' => (int) $teacherReserveCoin['lesson_coin'],
8940                'reserve_coin' => (int) $teacherReserveCoin['reserve_coin'],
8941                'reserve_coin_before_discount' => (int) $teacherReserveCoin['reserve_coin_before_discount'],
8942                'reserve_coin_with_op' => isset($teacherReserveCoin['display_native_option_amount_flg']) ? (int) $teacherReserveCoin['display_native_option_amount_flg'] : false,
8943                'displayNativeOptionAmountFlg' =>  isset($teacherReserveCoin['reserve_coin_with_op']) ? (int) $teacherReserveCoin['reserve_coin_with_op'] : null,
8944                'teacherCoinWithOp' => $teacherReserveCoin['reserve_coin_with_op'],
8945                'teacherCoinBeforeDiscount' => $teacherReserveCoin['reserve_coin_before_discount']
8946            ];
8947            $callanCoin = ($teacher->callan_halfprice_flg) ? $teacherCoinData['reserve_coin'] / 2 : $teacherCoinData['reserve_coin'];
8948            $teacherCoinData['callan_coin'] = (int) $callanCoin;
8949            $teacherCallanDiscount = $teacher->getCallanHalfPrice();
8950
8951            $sapuriCoin = 0;
8952            if ($this->isStudySapuriUser) {
8953                $teacherParams = array(
8954                    'teacher_id' => $teacher->id,
8955                    'current_rank_id' => $teacherCurrentRankId
8956                );
8957                $sapuriCoin = $this->Teacher->getStudySapuriCoin($teacherParams);
8958            }
8959
8960        }
8961
8962        $OS = myTools::getOSFromUA($_SERVER['HTTP_USER_AGENT'], TRUE);
8963
8964        // NJ-20069 - feature tag lists
8965        $feature_tags_list = [
8966            "new" => "新人講師",
8967            "best_free_talk" => "フリートークが得意",
8968            "good_in_teaching_textbook" => "教材レッスンが得意",
8969            "suitable_for_intermediate_or_advance_students" => "中/上級者向き",
8970            "have_many_beginner_students" => "初級者向き",
8971            "suitable_for_children" => "キッズ向き",
8972            "suitable_for_senior" => "シニア向き",
8973            "good_grammar_and_vocabulary" => "文法・ボキャブラリー",
8974            "good_for_first_timer" => "体験レッスン向き",
8975            "pronunciation" => "発音"
8976        ];
8977        $data = $this->User->findById($userId);
8978
8979        // NJ-17264
8980        $titleThresholdData = [];
8981
8982        $this->TitleThresholdTeacher->openDBReplica();
8983        $titleThresholdData = $this->TitleThresholdTeacher->find('first', [
8984            'fields'=>'TitleThresholdTeacher.title_type',
8985            'conditions' => array(
8986                'TitleThresholdTeacher.teacher_id' => $teacherId,
8987                'TitleThresholdTeacher.type = 1'
8988            ),
8989            'recursive' => -1
8990        ]);
8991        $this->TitleThresholdTeacher->closeDBReplica();
8992        // NJ-17264
8993
8994        $this->set('user',$data);
8995        $this->set('userOS', $OS);
8996        $this->set('localizeDir', $this->localizeDir);
8997        $this->set('teacherCoinData', $teacherCoinData);
8998        $this->set('lessonHistories', $lessonHistories);
8999        $this->set('teacherRates', $reserveAndCancel);
9000        $this->set('teacherOccupation', $teacherOccupation);
9001        $this->set('series', $return['series']);
9002        $this->set('feature', $return['feature']);
9003        $this->set('historyMonth', $historyMonth);
9004        $this->set('historyYear', $historyYear);
9005        $this->set('weekly_ratings', $get_weekly_rating['TeacherWeeklyRating']);
9006        $this->set('teacherId', $teacherId);
9007        $this->set('feature_tags_list', $feature_tags_list);
9008        $this->set('features', $this->teacherFeatures(true, $teacherId));
9009        $this->set('stusapLessonCount', (int) $teacher->stusap_lesson_count + (int) $teacher->stasapu_tos_lesson_count);
9010        $this->set('favoriteCount', $favoriteCount);
9011        $this->set('sapuriCoin', $sapuriCoin);
9012        $this->set('teacherCallanDiscount', empty($teacherCallanDiscount)? 0: $teacherCallanDiscount);
9013        $this->set('title_type', isset($titleThresholdData['TitleThresholdTeacher']['title_type']) ? $titleThresholdData['TitleThresholdTeacher']['title_type'] : 0);
9014
9015        $this->layout = 'mobile';
9016        $this->render('/Mobile/Teacher/detail');
9017    }
9018
9019
9020    //Retrieves the details of a specific avatar teacher for the mobile view in Native Camp. It returns various information about the teacher, including lesson history, reviews, and more.
9021    public function spAvatarDetail($teacherId) {
9022        if (!intval($teacherId)) {
9023            return $this->redirect(myTools::getUrl() . '/user/mobapp/retrypage');
9024        }
9025
9026        //fetch teacher data
9027        $data = $this->Teacher->findById($teacherId);
9028
9029        //no teacher data
9030        if (!$data) {
9031            return $this->redirect(myTools::getUrl() . '/user/mobapp/retrypage');
9032        }
9033
9034        // //check company ip and if the teacher is stealth on redirect to teacher list
9035        // if (!myTools::checkCompanyIP($_SERVER['REMOTE_ADDR']) && $data['Teacher']['stealth_flg']) {
9036        //     $this->redirect(array('controller' => 'SpTeacher', 'action' => 'index'));
9037        // }
9038
9039        if (BlockListTable::isUserBlocked($this->Auth->User('id'), $teacherId) == true) {
9040            return $this->redirect('/waiting');
9041        }
9042
9043        //lesson onair
9044        $onair1 = $this->LessonOnair->find('first', array(
9045            'fields' => array('LessonOnair.status', 'LessonOnair.connect_flg'),
9046            'conditions' => array('LessonOnair.teacher_id' => $data['Teacher']['id'])
9047            ));
9048
9049        //number of reservation
9050
9051        //teacher_status if login or break
9052        $teacherStatus1 = $this->TeacherStatus->find('first', array(
9053            'fields' => array('TeacherStatus.status', 'TeacherStatus.remarks1'),
9054            'conditions' => array('TeacherStatus.teacher_id' => $data['Teacher']['id']))
9055            );
9056        // get counrty details
9057        $teacherCountryDetails = $this->CountryCode->find('first', array(
9058            'fields' => array('country_name', 'nationality', 'code'),
9059            'conditions' => array('CountryCode.id' => $data['Teacher']['homeland2']))
9060            );
9061
9062        //get own reviews
9063        $selfReviews = array();
9064        $selfLessonCount = 0;
9065        $selfLessonNow = 0;
9066        $selfReservation = 0;
9067        $daysPast = 0;
9068        $userId = $this->Auth->user('id');
9069        if ($userId) {
9070            $this->set('user_lang',  $this->sharedUserData['User']['native_language2']);
9071            $selfReviews = $this->getUserReviews($userId, $teacherId);
9072            $userLessonDetail = $this->LessonOnairsLog->getUserLessonCount($userId, $teacherId);
9073            $selfLessonNow = $userLessonDetail['lessonCount'];
9074            $selfReservation = $userLessonDetail['reserveCount'];
9075            $selfLessonCount = $selfLessonNow + $selfReservation;
9076            $daysPast = $this->LessonOnairsLog->countDaysPast($userId, $teacherId);
9077        }
9078
9079        if (!empty($onair1)) {
9080            $onair = new LessonOnairTable($onair1['LessonOnair']);
9081        } elseif (!empty($teacherStatus1)) {
9082            $onair = new TeacherStatusTable($teacherStatus1['TeacherStatus']);
9083        } else {
9084            $onair = 0;
9085        }
9086
9087
9088        $this->set('onair', $onair);
9089        $this->set('teacher_id', $teacherId);
9090
9091        $teacher = new TeacherTable($data['Teacher']);
9092        $country = new TeacherTable($teacherCountryDetails['CountryCode']);
9093        $tutorCategory = new TeacherRankCoinTable($data['TeacherRankCoin']);
9094        $meta_desc = preg_replace('/\s+/', ' ', trim($teacher->getMetaMobile()));
9095        $this->set('teacher', $teacher);
9096
9097        # get weekly rating
9098        $get_weekly_rating = $this->UsersClassEvaluation->getAvatarRatings($teacherId);
9099        //number of lesson
9100        $lessonCount = (int)$teacher->lesson_count;
9101
9102        //number of lesson for all child accounts
9103        $lessonCount = $this->LessonOnairsLog->countTeacherLessons(['teacherId' => $teacherId, 'avatar' => 1]);
9104
9105        // Translate and save translated data
9106        $globalTranslate = TeacherTable::translate(array(
9107            'id' => $teacher->id,
9108            'lang'=> isset($this->localizeDir) ? $this->localizeDir : $this->lang_iso,
9109            'controller' => static::class
9110        ));
9111        $translatedMessageTranslation = isset($globalTranslate['message']) ? $globalTranslate['message'] : null;
9112        $translatedThirdppTranslation = isset($globalTranslate['self_introduction_third_pp']) ? $globalTranslate['self_introduction_third_pp'] : null;
9113        $this->set('message', $translatedMessageTranslation);
9114        $this->set('intro', $translatedThirdppTranslation);
9115
9116        // - prepare head text
9117        $headTextWD = $pageTitleWD  = $teacher->name;
9118        $metaDescWD = "";
9119
9120        //find the selfintro 
9121        $TeacherTable = new TeacherTable($teacher);
9122        $_userSelfIntro = $TeacherTable->iSNotDisplayHtmlTags($teacher->message);
9123        $_userSelfIntro = strip_tags($_userSelfIntro); 
9124
9125        if ($this->localizeDir == Configure::read('default.user_language')) {
9126            $headTextWD .= '('.$teacher->jp_name.')';
9127            $pageTitleWD .=  '('.$teacher->jp_name.')';
9128            //$metaDescWD .= '('.$teacher->jp_name.')';
9129        }
9130        $headTextWD .= '&ensp;' . __d('waiting', 'レッスン').':'.$lessonCount.__d('waiting', '回');
9131        $pageTitleWD .= '&ensp;' . sprintf(__d('waiting', 'レッスン:%s回 - 講師詳細 | オンライン英会話のネイティブキャンプ'), $lessonCount);
9132        //$metaDescWD .= '講師の紹介ページです。'.$teacher->getMetaDescription();
9133        $metaDescWD = TeacherTable::getMetaDescription2($_userSelfIntro);
9134
9135        //prepare meta image 
9136        $_teacherImgUrl = $teacher->getImageUrl();
9137
9138        //check if teacher has no image 
9139        if (empty($teacher->image_url) || !$teacher->image_url) {
9140            $defaultTeacherImg = myTools::getUrl() . '/teacher/img/no_profile_img.jpg';
9141            $_teacherImgUrl = ($_teacherImgUrl == $defaultTeacherImg) ? $_teacherImgUrl : $defaultTeacherImg;
9142        }
9143
9144
9145        // - set page meta information
9146        $this->set('headtext', $headTextWD);
9147        $this->set('title_for_layout', $pageTitleWD);
9148        $this->set('meta_description', $metaDescWD);
9149        $this->set('lessonCount', $lessonCount);
9150        $this->set('country', $country);
9151        //$this->set('rateBreakdown', $rateBreakdown);
9152        $this->set('selfReviews', $selfReviews);
9153        $this->set('selfLessonCount', $selfLessonCount);
9154        $this->set('daysPast', $daysPast);
9155        $this->set('meta_teacher_img',$_teacherImgUrl);
9156    
9157
9158        # get studydapuri textbooks
9159        $studysapuriType = Configure::read('studysapuri_textbook_category_types');
9160        if ( $this->studySapuriId && isset($this->sharedUserData['User']['payment_plan_id']) ) {
9161            $plan = myTools::studySapuriContractPlan($this->sharedUserData['User']['payment_plan_id']);
9162            $conArr['TextbookCategory.textbook_category_type'] = $studysapuriType[$plan];
9163        } elseif ($this->isStudySapuriTosUser) {
9164            $conArr['TextbookCategory.textbook_category_type'] = Configure::read('stasapu_tos_textbook_category_type');
9165        } else {
9166            $exCat = Configure::read('all_sapuri_textbook_category_types');
9167            $conArr['NOT'] = array('TextbookCategory.textbook_category_type' => $exCat);
9168        }
9169        
9170        $return = TeacherDetailTable::teacherIntroDetails($data, $this->localizeDir,$this->Auth->loggedIn(),$conArr);
9171
9172        [$historyYear, $historyMonth] = $teacher->getTotalTeachingExperience();
9173        $reserveAndCancel = $this->getReserveAndCancelled($teacherId);
9174        $lessonHistories = $this->getLessonHistory(true, $teacherId);
9175        $favoriteCount = $this->UsersFavorite->find('count', array('conditions' => array('UsersFavorite.teacher_id' => $teacherId)));
9176
9177        $teacherCurrentRankId = ClassRegistry::init('Teacher')->getTeacherCurrentRankId($teacherId);
9178
9179        // get user data
9180        $userData = isset($this->sharedUserData['User']) && $this->sharedUserData['User'] ? $this->sharedUserData['User'] : null;
9181
9182        $coinParams =  array(
9183            'current_rank_id' => $teacherCurrentRankId,
9184            'reserve_coin_data_id' => $teacher->reserve_coin_data_id,
9185            'reserve_coin_settings_flg' => $tutorCategory->reserve_coin_settings_flg,
9186            'student_native_option' => $userData['native_option'],
9187            'home_flg' => $teacher->home_flg,
9188            'counseling_flg' => $teacher->counseling_flg,
9189            'avatar_parent_flg' => $teacher->avatar_parent_flg,
9190            'avatar_flg' => $teacher->avatar_flg,
9191            'native_speaker_flg' => $teacher->native_speaker_flg
9192        );
9193
9194        // get teacher coin settings
9195        $teacherReserveCoin = $this->Teacher->getTeacherReserveCoin($coinParams);
9196        $teacherCoinData = [];
9197        if($teacherReserveCoin){
9198            // set teacher reservation coin
9199            $teacherCoinData = [
9200                'lesson_now' => (int) $teacherReserveCoin['lesson_coin'],
9201                'reserve_coin' => (int) $teacherReserveCoin['reserve_coin'],
9202                'reserve_coin_before_discount' => (int) $teacherReserveCoin['reserve_coin_before_discount'],
9203                'displayNativeOptionAmountFlg' => isset($teacherReserveCoin['display_native_option_amount_flg']) ? (int) $teacherReserveCoin['display_native_option_amount_flg'] : false,
9204                'reserve_coin_with_op' =>  isset($teacherReserveCoin['reserve_coin_with_op']) ? (int) $teacherReserveCoin['reserve_coin_with_op'] : null,
9205                'teacherCoinWithOp' => $teacherReserveCoin['reserve_coin_with_op'],
9206                'teacherCoinBeforeDiscount' => $teacherReserveCoin['reserve_coin_before_discount']
9207            ];
9208            $callanCoin = ($teacher->callan_halfprice_flg) ? $teacherCoinData['reserve_coin'] / 2 : $teacherCoinData['reserve_coin'];
9209            $teacherCoinData['callan_coin'] = (int) $callanCoin;
9210
9211            $teacherCallanDiscount = $teacher->getCallanHalfPrice();
9212
9213            $sapuriCoin = 0;
9214            if ($this->isStudySapuriUser) {
9215                $teacherParams = array(
9216                    'teacher_id' => $teacher->id,
9217                    'current_rank_id' => $teacherCurrentRankId
9218                );
9219                $sapuriCoin = $this->Teacher->getStudySapuriCoin($teacherParams);
9220            }
9221
9222        }
9223        
9224        // NJ-42412 - added feature also to spAvatarDetail (Related to NJ-20069)
9225        $feature_tags_list = [
9226            "new" => "新人講師",
9227            "best_free_talk" => "フリートークが得意",
9228            "good_in_teaching_textbook" => "教材レッスンが得意",
9229            "suitable_for_intermediate_or_advance_students" => "中/上級者向き",
9230            "have_many_beginner_students" => "初級者向き",
9231            "suitable_for_children" => "キッズ向き",
9232            "suitable_for_senior" => "シニア向き",
9233            "good_grammar_and_vocabulary" => "文法・ボキャブラリー",
9234            "good_for_first_timer" => "体験レッスン向き",
9235            "pronunciation" => "発音"
9236        ];
9237        $this->set('teacherCoinData', $teacherCoinData);
9238        $this->set('lessonHistories', $lessonHistories);
9239        $this->set('teacherRates', $reserveAndCancel);
9240        $this->set('series', $return['series']);
9241        $this->set('features', json_encode((array)$return['feature']));
9242        $this->set('historyMonth', $historyMonth);
9243        $this->set('historyYear', $historyYear);
9244        $this->set('weekly_ratings', isset($get_weekly_rating) ? $get_weekly_rating['TeacherWeeklyRating'] : 0);
9245        $this->set('teacherId', $teacherId);
9246        $this->set('avatarId', $this->isAvatar($teacherId));
9247        $this->set('favoriteCount', $favoriteCount);
9248        $this->set('feature_tags_list', $feature_tags_list);
9249        $this->set('sapuriCoin', $sapuriCoin);
9250        $this->set('teacherCallanDiscount', empty($teacherCallanDiscount)? 0: $teacherCallanDiscount);
9251        $this->layout = 'mobile';
9252        $this->render('/Mobile/Teacher/avatar_detail');
9253    }
9254
9255    /**
9256     * @api {get} /user/:language/avatar_detail/:teacherId/:highLightFlag avatar_detail()
9257     * @apiName avatar_detail
9258     * @apiGroup Waiting
9259     * @apiDescription Retrieves the details of a specific avatar teacher in Native Camp. It returns various information about the teacher, including lesson history, reviews, and more.
9260     *
9261     * @apiParam {String} language The language code for the page.
9262     * @apiParam {String} teacherId The ID of the avatar teacher.
9263     * @apiParam {Boolean} [highLightFlag] Indicates whether to highlight certain elements on the page.
9264     * 
9265     * @apiSuccess {Object} teacher The teacher information.
9266     * @apiSuccess {String} teacher.id The ID of the teacher.
9267     * @apiSuccess {String} teacher.name The name of the teacher.
9268     * @apiSuccess {String} teacher.jp_name The Japanese name of the teacher.
9269     * @apiSuccess {String} teacher.image_url The URL of the teacher's image.
9270     * @apiSuccess {Object} country The country information.
9271     * @apiSuccess {String} country.country_name The name of the country.
9272     * @apiSuccess {String} country.national The nationality.
9273     * @apiSuccess {Object} timezone The timezone information.
9274     * @apiSuccess {String} timezone.timezone The timezone.
9275     * @apiSuccess {Object} tutorCategory The tutor category information.
9276     * @apiSuccess {Number} tutorCategory.coins The number of coins the teacher has.
9277     * @apiSuccess {Number} tutorCategory.limited_plan_reservation Indicates whether the teacher has a limited plan reservation (0: No, 1: Yes).
9278     * @apiSuccess {Number} timeDiff The time difference between the user's local time and the teacher's time.
9279     * @apiSuccess {Object} onair The on-air lesson information.
9280     * @apiSuccess {Number} onair.status The status of the on-air lesson.
9281     * @apiSuccess {Number} onair.connect_flg Indicates whether the teacher is connected (1: Yes, 0: No).
9282     * @apiSuccess {Number} teacherCoin The coin amount for the teacher.
9283     * @apiSuccess {Number} callanCoin The Callan coin amount for the teacher.
9284     * @apiSuccess {Number} teacherCallanDiscount The Callan discount for the teacher.
9285     * @apiSuccess {Number} lessonCount The number of lessons the teacher has conducted.
9286     * @apiSuccess {Number} historyYear The number of years the teacher has been teaching.
9287     * @apiSuccess {Number} historyMonth The number of months the teacher has been teaching.
9288     * @apiSuccess {Object} keep_memo The memo kept by the user for the teacher.
9289     * @apiSuccess {String} keep_memo.memo The memo text.
9290     * @apiSuccess {Object} reserveAndCancel The reservation and cancellation breakdown.
9291     * @apiSuccess {Number} reserveAndCancel.reserve The number of reservations.
9292     * @apiSuccess {Number} reserveAndCancel.cancel The number of cancellations.
9293     * @apiSuccess {Object} lessonHistory The lesson history of the teacher.
9294     * @apiSuccess {Number} lessonHistoryCount The count of lessons in the lesson history.
9295     * @apiSuccess {Object} latestUserLesson The latest lesson taken by the user with the teacher.
9296     * @apiSuccess {Number} latestUserLesson.id The ID of the lesson.
9297     * @apiSuccess {Number} latestUserLesson.teacher_id The ID of the teacher.
9298     * @apiSuccess {Number} latestUserLesson.user_id The ID of the user.
9299     * @apiSuccess {Number} teacherFavoriteCount The count of users who have favorited the teacher.
9300     * @apiSuccess {Number} stusapLessonCount The count of Study Sapuri lessons conducted by the teacher.
9301     * @apiSuccess {Object[]} album The album of images for the teacher.
9302     * @apiSuccess {Number} album.id The ID of the image.
9303     * @apiSuccess {String} album.image_url The URL of the image.
9304     * @apiSuccess {Object} oOnair The on-air status of the teacher.
9305     * @apiSuccess {Number} oOnair.status The status of the on-air lesson.
9306     * @apiSuccess {String} oOnair.remarks1 Remarks about the on-air lesson.
9307     * @apiSuccess {Boolean} isFav Indicates whether the user has favorited the teacher.
9308     * @apiSuccess {Number} favoriteCount The count of users who have favorited the teacher.
9309     * @apiSuccess {Object} feature The features of the teacher.
9310     * @apiSuccess {Boolean} feature.new Indicates whether the teacher is new.
9311     * @apiSuccess {Boolean} feature.best_free_talk Indicates whether the teacher is best for free talk.
9312     * @apiSuccess {Boolean} feature.good_in_teaching_textbook Indicates whether the teacher is good in teaching textbooks.
9313     * @apiSuccess {Boolean} feature.suitable_for_intermediate_or_advance_students Indicates whether the teacher is suitable for intermediate or advanced students.
9314     * @apiSuccess {Boolean} feature.have_many_beginner_students Indicates whether the teacher has many beginner students.
9315     * @apiSuccess {Boolean} isHide Indicates whether the teacher is hidden by the user.
9316     * @apiSuccess {Boolean} unsupportedBrowser Indicates whether the user's browser is unsupported.
9317     * @apiSuccess {Boolean} canReport Indicates whether the user can report the teacher.
9318     * @apiSuccess {String} reservationTextbookConnectId The ID of the textbook connect for the reservation.
9319     * @apiSuccess {Boolean} hideLimitedPlanReservation Indicates whether to hide the limited plan reservation.
9320     * @apiSuccess {Boolean} firstTimeLoggedIn Indicates whether it is the user's first time logging in.
9321     * @apiSuccess {Number} velifyCount The count of phone verification checks.
9322     * @apiSuccess {Object[]} countryCodes The list of country codes.
9323     * @apiSuccess {String} countryCodes.country_name The name of the country.
9324     * @apiSuccess {String} countryCodes.nationality The nationality.
9325     * @apiSuccess {String} countryCodes.code The country code.
9326     * @apiSuccess {Object} userCountry The country information of the user.
9327     * @apiSuccess {String} userCountry.country_name The name of the country.
9328     * @apiSuccess {String} userCountry.national The nationality.
9329     * @apiSuccess {String} userCountry.code The country code.
9330     * @apiSuccess {Boolean} paidParent Indicates whether the user is a paid parent.
9331     * @apiSuccess {String} headtext The head text for the page.
9332     * @apiSuccess {String} title_for_layout The title for the page layout.
9333     * @apiSuccess {String} meta_description The meta description for the page.
9334     * @apiSuccess {String} meta_keywords The meta keywords for the page.
9335     * @apiSuccess {String} meta_teacher_img The URL of the teacher's image for meta tags.
9336     * @apiSuccess {Object[]} selfReviews The self-reviews of the user for the teacher.
9337     * @apiSuccess {Number} selfLessonCount The count of lessons taken by the user with the teacher.
9338     * @apiSuccess {Number} daysPast The number of days past since the user's last lesson with the teacher.
9339     * @apiSuccess {Object[]} reviews The reviews of the teacher.
9340     * @apiSuccess {Number} reviews.commentCount The count of comments for the teacher.
9341     * @apiSuccess {Number} reviews.approveEvalFlag The flag indicating the approval status of the evaluations.
9342     * @apiSuccess {Number} commentCount The count of comments for the teacher.
9343     * @apiSuccess {Number} approveEvalFlag The flag indicating the approval status of the evaluations.
9344     * @apiSuccess {Object} weekly_ratings The weekly ratings of the teacher.
9345     * @apiSuccess {Number} weekly_ratings.TeacherWeeklyRating.id The ID of the weekly rating.
9346     * @apiSuccess {Number} weekly_ratings.TeacherWeeklyRating.teacher_id The ID of the teacher.
9347     * @apiSuccess {Number} weekly_ratings.TeacherWeeklyRating.week The week of the rating.
9348     * @apiSuccess {Number} weekly_ratings.TeacherWeeklyRating.year The year of the rating.
9349     * @apiSuccess {Number} weekly_ratings.TeacherWeeklyRating.rating The rating.
9350     * @apiSuccess {Object} translatedMessageParams The translated message parameters.
9351     * @apiSuccess {String} translatedMessageParams.translatedMessage The translated message.
9352     * @apiSuccess {Object} translatedSelfIntroductionThirdPpParams The translated self-introduction parameters.
9353     * @apiSuccess {String} translatedSelfIntroductionThirdPpParams.translatedSelfIntroductionThirdPp The translated self-introduction.
9354     * @apiSuccess {Object} translationModel The translation model.
9355     * @apiSuccess {Number} translationModel.id The ID of the translation.
9356     * @apiSuccess {Number} translationModel.teacher_id The ID of the teacher.
9357     * @apiSuccess {String} translationModel.lang The language of the translation.
9358     * @apiSuccess {String} translationModel.controller The controller of the translation.
9359     * @apiSuccess {Number} teacherCoinBeforeDiscount The coin amount for the teacher before discount.
9360     * @apiSuccess {Number} teacherCoinWithOp The coin amount for the teacher with options.
9361     * @apiSuccess {Boolean} nativeOptionFlg Indicates whether the native option is enabled.
9362     * @apiSuccess {Object} preset The preset textbook information.
9363     * @apiSuccess {String} preset.textbookConnectId The ID of the textbook connect.
9364     * @apiSuccess {String} preset.textbookCategoryTypeId The type ID of the textbook category.
9365     * @apiSuccess {String} textbookConnectId The ID of the textbook connect.
9366     * @apiSuccess {String} textbookCategoryTypeId The type ID of the textbook category.
9367     * @apiSuccess {Object[]} apologyList The list of apologies for reservation cancellations.
9368     * @apiSuccess {Number} apologyList.id The ID of the apology.
9369     * @apiSuccess {String} apologyList.apology The apology text.
9370     * @apiSuccess {Object} disabledSchedule The disabled schedule information.
9371     * @apiSuccess {Boolean} disabledSchedule.disabled Indicates whether the schedule is disabled.
9372     * @apiSuccess {Boolean} showNoticeMaxLimit Indicates whether to show the notice for the maximum limit.
9373     * @apiSuccess {Boolean} noIndexFlgOveride Indicates whether to override the no-index flag.
9374     * @apiSuccess {Boolean} enableNextTextbookChapterButton Indicates whether to enable the next textbook chapter button.
9375     * @apiSuccess {String} chatHash The chat hash for the lesson.
9376     * @apiSuccess {Number} lessonRequestFlg The flag indicating the lesson request status.
9377     *
9378     * @apiSuccessExample {json} Success-Response:
9379     *     {
9380     *         "teacher": {
9381     *             "id": 520,
9382     *             "name": "Teacher Name",
9383     *             "jp_name": "Teacher Name",
9384     *             "image_url": "http://example.com/image.jpg"
9385     *         },
9386     *         "country": {
9387     *             "country_name": "Country Name",
9388     *             "national": "National"
9389     *         },
9390     *         "timezone": {
9391     *             "timezone": "Asia/Tokyo"
9392     *         },
9393     *         "tutorCategory": {
9394     *             "coins": 100,
9395     *             "limited_plan_reservation": 0
9396     *         },
9397     *         "timeDiff": 32400,
9398     *         "onair": {
9399     *             "status": 1,
9400     *             "connect_flg": 1
9401     *         },
9402     *         "teacherCoin": 100,
9403     *         "callanCoin": 50,
9404     *         "teacherCallanDiscount": 20,
9405     *         "lessonCount": 10,
9406     *         "historyYear": 2,
9407     *         "historyMonth": 3,
9408     *         "keep_memo": {
9409     *             "memo": "Memo"
9410     *         },
9411     *         "reserveAndCancel": {
9412     *             "reserve": 5,
9413     *             "cancel": 2
9414     *         },
9415     *         "lessonHistory": {},
9416     *         "lessonHistoryCount": 5,
9417     *         "latestUserLesson": {
9418     *             "id": 123,
9419     *             "teacher_id": 520,
9420     *             "user_id": 456
9421     *         },
9422     *         "teacherFavoriteCount": 100,
9423     *         "stusapLessonCount": 50,
9424     *         "album": [
9425     *             {
9426     *                 "id": 1,
9427     *                 "image_url": "http://example.com/image1.jpg"
9428     *             }
9429     *         ],
9430     *         "oOnair": {
9431     *             "status": 1,
9432     *             "remarks1": "Remarks"
9433     *         },
9434     *         "isFav": true,
9435     *         "favoriteCount": 200,
9436     *         "feature": {
9437     *             "new": true,
9438     *             "best_free_talk": true,
9439     *             "good_in_teaching_textbook": true,
9440     *             "suitable_for_intermediate_or_advance_students": true,
9441     *             "have_many_beginner_students": true
9442     *         },
9443     *         "isHide": false,
9444     *         "unsupportedBrowser": false,
9445     *         "canReport": true,
9446     *         "reservationTextbookConnectId": "123",
9447     *         "hideLimitedPlanReservation": false,
9448     *         "firstTimeLoggedIn": true,
9449     *         "velifyCount": 1,
9450     *         "countryCodes": [
9451     *             {
9452     *                 "country_name": "Country Name",
9453     *                 "nationality": "National",
9454     *                 "code": "Code"
9455     *             }
9456     *         ],
9457     *         "userCountry": {
9458     *             "country_name": "Country Name",
9459     *             "national": "National",
9460     *             "code": "Code"
9461     *         },
9462     *         "paidParent": false,
9463     *         "headtext": "Teacher Name",
9464     *         "title_for_layout": "Teacher Name - 講師詳細 | オンライン英会話のネイティブキャンプ",
9465     *         "meta_description": "Teacher description",
9466     *         "meta_keywords": "Teacher Name,講師,オンライン英会話,ネイティブキャンプ",
9467     *         "meta_teacher_img": "http://example.com/image.jpg",
9468     *         "selfReviews": [...],
9469     *         "selfLessonCount": 5,
9470     *         "daysPast": 10,
9471     *         "reviews": [
9472     *             {
9473     *                 "commentCount": 50,
9474     *                 "approveEvalFlag": 1
9475     *             }
9476     *         ],
9477     *         "commentCount": 50,
9478     *         "approveEvalFlag": 1,
9479     *         "weekly_ratings": {
9480     *             "TeacherWeeklyRating": {
9481     *                 "id": 123,
9482     *                 "teacher_id": 520,
9483     *                 "week": 1,
9484     *                 "year": 2021,
9485     *                 "rating": 5
9486     *             }
9487     *         },
9488     *         "translatedMessageParams": {
9489     *             "translatedMessage": "Translated message"
9490     *         },
9491     *         "translatedSelfIntroductionThirdPpParams": {
9492     *             "translatedSelfIntroductionThirdPp": "Translated self-introduction"
9493     *         },
9494     *         "translationModel": {
9495     *             "id": 123,
9496     *             "teacher_id": 520,
9497     *             "lang": "en",
9498     *             "controller": "WaitingController"
9499     *         },
9500     *         "teacherCoinBeforeDiscount": 120,
9501     *         "teacherCoinWithOp": 130,
9502     *         "nativeOptionFlg": true,
9503     *         "preset": {
9504     *             "textbookConnectId": "456",
9505     *             "textbookCategoryTypeId": "789"
9506     *         },
9507     *         "textbookConnectId": "456",
9508     *         "textbookCategoryTypeId": "789",
9509     *         "apologyList": [
9510     *             {
9511     *                 "id": 1,
9512     *                 "apology": "Apology"
9513     *             }
9514     *         ],
9515     *         "disabledSchedule": {
9516     *             "disabled": true
9517     *         },
9518     *         "showNoticeMaxLimit": false,
9519     *         "noIndexFlgOveride": false,
9520     *         "enableNextTextbookChapterButton": true,
9521     *         "chatHash": "example_chat_hash",
9522     *         "lessonRequestFlg": 1
9523     *     }
9524     *
9525     * @apiError {String} error Message indicating the error.
9526     *
9527     * @apiErrorExample {json} Error-Response:
9528     *     {
9529     *         "error": "Invalid request."
9530     *     }
9531     * 
9532     * @apiSampleRequest off
9533     */
9534    public function avatar_detail($teacherId = 520, $highLightFlag = null) {
9535        if (is_null($teacherId)) {
9536            return $this->redirect(myTools::getUrl() . '/user/waiting', 301);
9537        }
9538
9539        $this->avatarLatestLessonHistory($this->Auth->user('id'), $teacherId);
9540        //set mobile view
9541        if (myTools::defaultAction($this)) {
9542            return $this->spAvatarDetail($teacherId);
9543        }
9544
9545        $checkParams = array(
9546            'type' => 'count',
9547            'args' => array(
9548                'conditions' => array(
9549                    'id' => $teacherId,
9550                    'avatar_parent_flg' => 0
9551                ),
9552                'recursive' => -1
9553            )
9554        );
9555
9556        // - NC-3802: redirect to mypage if not avatar parent teacher
9557        if ($this->Teacher->getTeachers($checkParams)) {
9558            return $this->redirect('/mypage');
9559        }
9560
9561        if (BlockListTable::isUserBlocked($this->Auth->User('id'), $teacherId) == true) {
9562            return $this->redirect('/waiting');
9563        }
9564        //redirect to proper profile
9565        $this->checkProperProfile($teacherId);
9566
9567        $this->Teacher->unbindModel(array('hasOne' => array('LessonOnair')));
9568        $queryCondition = array(
9569            'fields' => array(
9570                    'TeacherRankCoin.coins',
9571                    'LessonOnair.id',
9572                    'LessonOnair.teacher_id',
9573                    'LessonOnair.user_id',
9574                    'TeacherRankCoin.limited_plan_reservation'
9575                ),
9576            'joins' => array(
9577                array(
9578                    'type' => 'LEFT',
9579                    'table' => 'teacher_rank_coins',
9580                    'alias' => 'TeacherRankCoin',
9581                    'conditions' => array('Teacher.rank_coin_id = TeacherRankCoin.id AND TeacherRankCoin.status')
9582                )
9583            ),
9584            'conditions' => array(
9585                array('Teacher.id' => $teacherId)
9586            ),
9587            'show' => 'first'
9588        );
9589
9590        $commonTeacherStatusParams = array(
9591            'page_display' => 'listTeacher',
9592            'query_conditions' => $queryCondition
9593        );
9594        $data = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
9595
9596        if (!$data) {
9597            return $this->redirect('/waiting/');
9598        }
9599
9600        //redirect if withdrawn teacher or teacher is block in NJ-43859
9601        if ($data['Teacher']['status'] <> 1  || $data['Teacher']['inactive_flg'] == 1 || in_array($data['Teacher']['rank_coin_id'], $this->blockMemberSettings)) {
9602            if ($this->Auth->loggedIn()) {
9603                return $this->redirect(myTools::geturl() . '/mypage');
9604            } else {
9605                return $this->redirect(myTools::geturl() . '/waiting');
9606            }
9607        }
9608
9609        if (isset($data['LessonOnair'])) {
9610            $tmp = (object) $data['LessonOnair'];
9611            if (!$tmp->id) {
9612                $data['LessonOnair'] = null;
9613            }
9614        }
9615
9616
9617
9618        // get teacher information
9619        $teacher = new TeacherTable($data['Teacher']);
9620
9621        $country = new TeacherTable($data['CountryCode']);
9622        $timezone = new TimezoneTable($data['Timezone']);
9623        $tutorCategory = new TeacherRankCoinTable($data['TeacherRankCoin']);
9624
9625        // Avatar var
9626        $avatarTeacherId = $teacherId;
9627        $teacherName = isset($teacher->jp_name) ? $teacher->jp_name : null;
9628        $teacherNameEn = isset($teacher->name) ? $teacher->name : null;
9629        $teacherImageSrc = $teacher->getImageUrl();
9630
9631        $timeDiff = 0;
9632        if (isset($timezone->continent_id) && isset($timezone->city_eng)) {
9633            $timeDiffData = $this->Timezone->computeTimeDiff(array(
9634                'continent_id' => $timezone->continent_id,
9635                'city' => $timezone->city_eng
9636            ));
9637
9638            //
9639            if ($timeDiffData['success']) {
9640                $timeDiff = $timeDiffData['timeDiff'];
9641            }
9642        }
9643
9644        $onair = $data['LessonOnair'];
9645
9646        $teacherCurrentRankId = ClassRegistry::init('Teacher')->getTeacherCurrentRankId($teacher->id);
9647        # Get teachers reservation amounts.
9648        $req_params =  array(
9649                'basic_amount_type' => 15,
9650                'current_rank_id' => $teacherCurrentRankId
9651            );
9652        $teacherCoin = $this->HomeBasedRankBasicAmountLog->getBasicAmount($req_params);
9653
9654        //
9655        $teacherCurrentRankId = ClassRegistry::init('Teacher')->getTeacherCurrentRankId($teacher->id);
9656
9657        // get user data
9658        $userData = isset($this->sharedUserData['User']) && $this->sharedUserData['User'] ? $this->sharedUserData['User'] : null;
9659
9660        # Get teachers reservation amounts. | NJ-2038, for hb teachers only not applicable for counselor/avatar
9661        $coinParams =  array(
9662            'current_rank_id' => $teacherCurrentRankId,
9663            'reserve_coin_data_id' => $teacher->reserve_coin_data_id,
9664            'reserve_coin_settings_flg' => $tutorCategory->reserve_coin_settings_flg,
9665            'student_native_option' => $userData['native_option'],
9666            'home_flg' => $teacher->home_flg,
9667            'counseling_flg' => $teacher->counseling_flg,
9668            'avatar_parent_flg' => $teacher->avatar_parent_flg,
9669            'avatar_flg' => $teacher->avatar_flg,
9670            'native_speaker_flg' => $teacher->native_speaker_flg
9671        );
9672
9673        // get teacher coin settings
9674        $teacherCoinData = $this->Teacher->getTeacherReserveCoin($coinParams);
9675
9676        $teacherCoinWithOp = $teacherCoinBeforeDiscount = null;
9677        $displayNativeOptionAmountFlg = false;
9678        if($teacherCoinData){
9679            // set teacher reservation coin
9680            $teacherCoin = (isset($teacherCoinData['reserve_coin']) && is_numeric($teacherCoinData['reserve_coin'])) ? $teacherCoinData['reserve_coin'] : 0;
9681            $teacherCoinBeforeDiscount = $teacherCoinData['reserve_coin_before_discount'];
9682            $teacherCoinWithOp = $teacherCoinData['reserve_coin_with_op'];
9683            $displayNativeOptionAmountFlg = $teacherCoinData['display_native_option_amount_flg'];
9684        }
9685
9686        $callanCoin = ($teacher->callan_halfprice_flg) ? $teacherCoin / 2 : $teacherCoin;
9687
9688        $teacherCallanDiscount = $teacher->getCallanHalfPrice();
9689
9690        $userId = ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null;
9691
9692        //number of lesson
9693        $lessonCount = $this->LessonOnairsLog->countTeacherLessons(['teacherId' => $teacherId, 'avatar' => 1]);
9694
9695        [$historyYear, $historyMonth] = $teacher->getTotalTeachingExperience();
9696
9697        $this->set('historyMonth',$historyMonth);
9698        $this->set('historyYear',$historyYear);
9699
9700        //NJ-20069 avatar detail changes
9701        $getKeepMemo = $this->UsersMemo->find('first', array(
9702            'fields' => array(
9703                'id',
9704                'memo'
9705            ),
9706            'conditions' => array(
9707                'user_id' => $this->Auth->user('id'),
9708                'teacher_id' => $teacherId,
9709                'type' => 0
9710            ),
9711            'order' => array('created DESC'),
9712        ));
9713
9714        $this->set('keep_memo', $getKeepMemo);
9715
9716        $reserveAndCancel = $this->getReserveAndCancelled($teacherId);
9717        $lessonHistory = $this->LessonSchedule->latestLessonHistory($teacherId, $this->Auth->user('id'), $this->localizeDir, null, "avatar");
9718        $lessonHistoryCount  = is_iterable(($lessonHistory['lessonHistory'])) ? count($lessonHistory['lessonHistory']) : 0;
9719        $latestUserLesson = ($lessonHistory['lessonHistory'][0]['LessonOnairsLog']);
9720        $teacherFavoriteCount = $this->UsersFavorite->getFavoriteCount($teacherId);
9721        $stusapLessonCount = $this->Teacher->getAvatarSapuriLessonCount($teacherId);
9722
9723        // - if has translated Category name
9724        if (isset($lessonHistory['lessonHistory'][0]['GlobalTextbookCategory']['gl_name']) && $lessonHistory['lessonHistory'][0]['GlobalTextbookCategory']['gl_name']) {
9725            $lessonHistory['lessonHistory'][0]['TextbookCategory']['name'] = $lessonHistory['lessonHistory'][0]['GlobalTextbookCategory']['gl_name'];
9726        }
9727
9728        $formattedLatestLessonData = "";
9729        if(!empty($latestUserLesson))
9730        $formattedLatestLessonData = date('Y-m-d',strtotime($latestUserLesson['start_time'])). " (" . date('D',strtotime($latestUserLesson['start_time'])) . ") ";
9731
9732        $this->set('lessonHistoryCount', $lessonHistoryCount);
9733        $this->set('latestUserLesson', $lessonHistory['lessonHistory'][0]);
9734        $this->set('teacherRates', $reserveAndCancel);
9735        $this->set('teacherIdCheck', $teacherId);
9736        $this->set('latestLessonData', $formattedLatestLessonData);
9737        $this->set('lessonHistory', $lessonHistory);
9738        $this->set('teacherId', $teacherId);
9739        $this->set('teacherFavoriteCount', $teacherFavoriteCount);
9740        $this->set('stusapLessonCount', $stusapLessonCount);
9741        $this->set('stusapLessonCount', (int) $teacher->stusap_lesson_count + (int) $teacher->stasapu_tos_lesson_count);
9742
9743
9744
9745        // album
9746        $this->TeacherImage->openDBReplica();
9747        $album = $this->TeacherImage->find('all', array(
9748            'fields' => array(
9749                'TeacherImage.id',
9750                'TeacherImage.teacher_id',
9751                'TeacherImage.approve_flg',
9752                'TeacherImage.is_profile',
9753                'TeacherImage.approve_required',
9754                'FileStorage.url'
9755            ),
9756            'conditions' => array(
9757                'TeacherImage.teacher_id' => $teacherId,
9758                'TeacherImage.is_profile' => 0,
9759                'OR' => array(
9760                    'OR' => array(
9761                            'TeacherImage.approve_flg' => 1,
9762                            'TeacherImage.approve_required' => 0
9763                        )
9764                    )
9765            ),
9766            'joins' => array(
9767                array(
9768                    'type' => 'INNER',
9769                    'table' => 'file_storage',
9770                    'alias' => 'FileStorage',
9771                    'conditions' => array(
9772                        'TeacherImage.file_storage_id = FileStorage.id',
9773                        'FileStorage.uploader_type = 3',
9774                        'FileStorage.uploader_id' => $teacherId
9775                    )
9776                )
9777            ),
9778            'order' => array('TeacherImage.id DESC')
9779        ));
9780        $this->TeacherImage->closeDBReplica();
9781
9782        $this->set('album', $album);
9783
9784        //lesson onair
9785        if (!empty($onair)) {
9786            $oOnair = new LessonOnairTable($onair);
9787        } else {
9788            //teacher_status if login or break
9789            $teacherStatus1 = $this->TeacherStatus->find('first', array(
9790                'fields' => array('TeacherStatus.status', 'TeacherStatus.remarks1', 'TeacherStatus.remarks2'),
9791                'conditions' => array('TeacherStatus.teacher_id' => $teacher->getId())
9792            ));
9793            if (!empty($teacherStatus1)) {
9794                $oOnair = new TeacherStatusTable($teacherStatus1['TeacherStatus']);
9795            } else {
9796                $oOnair = 0;
9797            }
9798        }
9799
9800        //favorite
9801        $where = array(
9802            'UsersFavorite.user_id'     => $this->Auth->user('id'),
9803            'UsersFavorite.teacher_id'     => $teacherId,
9804        );
9805        $isFav = $this->UsersFavorite->find('count', array('conditions' => $where));
9806        $where = array(
9807            'UsersFavorite.teacher_id'  => $teacherId,
9808        );
9809        $favoriteCount = $this->UsersFavorite->find('count', array('conditions' => $where));
9810        $where = array(
9811            'TeacherFeature.teacher_id' => $teacherId,
9812        );
9813        $feature = $this->TeacherFeature->find('first', array('conditions' => $where));
9814
9815        // NC-5897 : check if teacher was hide by user.
9816        $where = array(
9817            'user_id' => $this->Auth->user('id'),
9818            'teacher_id' => $teacherId,
9819        );
9820        $isHide = $this->BlockList->isTeacherHide($where);
9821
9822        $feature = isset($feature['TeacherFeature']) ? new TeacherFeatureTable($feature['TeacherFeature']) : new TeacherFeatureTable(array());
9823        $this->User->recursive = -1;
9824        $data = $this->User->findById($userId);
9825        $user = isset($data['User'])?$data['User']: null;
9826        $unsupportedBrowser = false;
9827        $browser =  $this->request->header('User-Agent');
9828
9829        if (preg_match('/(Edg|Edge)/i',$browser) ) {
9830            $unsupportedBrowser = false;
9831        } elseif (!preg_match('/(Chrome|Firefox|Safari)/i',$browser)) {
9832            $unsupportedBrowser = true;
9833        }
9834        $canReport = true;
9835        $reservationTextbookConnectId = "";
9836        if ($user) {
9837            $userData = new UserTable($data['User']);
9838            $userMembership = $userData->getUserMembership();
9839            $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($userData->payment_plan_id);
9840            $this->set('user_lang', $userData->native_language2);
9841            // if weekly plan user
9842            $corporateUser = isset($corporateType) ? $corporateType : '';
9843
9844            $userMemberTypeCantReportTeacher = Configure::read('user_member_type.cant_report_teacher');
9845            $canReport = $userData->getMembershipTypeIndex();
9846            $canReport = in_array($canReport, $userMemberTypeCantReportTeacher) ? false : true;
9847            //NJ-24096: get last reservation textbook type
9848            $sapuriFlg = ($this->isStudySapuriTosUser || $this->isStudySapuriUser) ? true :false;
9849            $lastReservationData = LessonScheduleTable::getLastReservation($userId, $sapuriFlg);
9850
9851            if (!empty($lastReservationData['LessonSchedule']['connect_id'])) {
9852                $reservationTextbookConnectId = $lastReservationData['LessonSchedule']['connect_id'];
9853            } else {
9854                $this->User->openDBReplica();
9855                $checkUserFirstFlg = $this->LessonSchedule->field('connect_id', array('user_id' => $userId));
9856                $this->User->closeDBReplica();
9857                if (empty($checkUserFirstFlg)) {
9858                    $defaultParams = array(
9859                        'user_id' => $userId,
9860                        'lang' => $userData->native_language2
9861                    );
9862                    $defaultReservation = $this->Textbook->getDefaultReservationTBConnectId($defaultParams);
9863                    if ($defaultReservation) {
9864                        $reservationTextbookConnectId = $defaultReservation;
9865                    }
9866                }
9867            }
9868        }
9869        $this->set(compact('reservationTextbookConnectId'));
9870        $this->set('unsupportedBrowser', $unsupportedBrowser);
9871        // NC-6615 check if user can report the teacher
9872        $this->set('canReport', $canReport);
9873
9874        $hideLimitedPlanReservation = false;
9875        if ($tutorCategory->limited_plan_reservation == 0 && (isset($corporateUser) && $corporateUser ==  Configure::read('corporate_type.limited'))) {
9876            $hideLimitedPlanReservation = true;
9877        }
9878
9879        $firstTimeLoggedIn = false;
9880        if (!$user['last_login_time']) {
9881            $firstTimeLoggedIn = true;
9882        }
9883
9884        $paidParent = false;
9885
9886        $velifyCount = $this->PhoneVerifyCheckLog->find('count',array(
9887            'conditions' => array(
9888                'user_id' => $this->Auth->user('id'),
9889                'status' => 0
9890            )
9891        ));
9892
9893        $countryCodes = $this->CountryCode->find('all',array(
9894            'fields' => array(
9895                'code',
9896                'country_name'
9897            ),
9898            'order' => 'country_name ASC'
9899        ));
9900        $this->set('countryCodes',$countryCodes);
9901
9902        $userCountry['CountryCode']['country_name'] = '';
9903        $userCountry['CountryCode']['code'] = '';
9904        if(!empty($data['User']['country_code'])){
9905            $userCountry = $this->CountryCode->find('first',array(
9906                'conditions' => array(
9907                    'code' => $data['User']['country_code']),
9908                'fields' => array(
9909                    'code',
9910                    'country_name')
9911            ));
9912            if(empty($userCountry)){
9913                $userCountry['CountryCode']['code'] = '';
9914            }
9915        }
9916        $this->set('countryCodes',$countryCodes);
9917
9918        //check if user is child by checking its parent id not empty
9919        if (isset($data['User']['parent_id'])) {
9920            $paidParent = $this->User->checkPaidParent($data['User']['parent_id']);
9921        }
9922        #$lesson_count=0;
9923        // 管理者権限会員は無制限でレッスン出来る
9924        if ($user['admin_flg']=='1') {
9925            $user['charge_flg'] = 1;
9926            $lesson_count=0;
9927            $lesson_count_today = 0;
9928        }
9929
9930        if (empty($user['enquate6'])) {
9931            $user['enquate6'] = '1';
9932        }
9933
9934        if (empty($user['enquate7'])) {
9935            $user['enquate7'] = '1';
9936        }
9937        // - prepare head text
9938        $headTextWD = $pageTitleWD = $teacherNameEn;
9939        $metaDescWD = "";
9940        if ($this->localizeDir == Configure::read('default.user_language')) {
9941            $headTextWD .= '('.$teacherName.')';
9942            $pageTitleWD .=  '('.$teacherName.')';
9943            //$metaDescWD .= '('.$teacherName.')';
9944        }
9945        $pageTitleWD .= '&ensp;-&ensp;'. __d('default_pc','講師詳細 | オンライン英会話のネイティブキャンプ');
9946        //$metaDescWD .= __d('waiting','講師の紹介ページです。').$teacher->getMetaDescription();
9947
9948        //prepare meta image 
9949        $_teacherImgUrl = $teacher->getImageUrl();
9950
9951        //check if teacher has no image 
9952        if (empty($teacher->image_url) || !$teacher->image_url) {
9953            $defaultTeacherImg = myTools::getUrl() . '/teacher/img/no_profile_img.jpg';
9954            $_teacherImgUrl = ($_teacherImgUrl == $defaultTeacherImg) ? $_teacherImgUrl : $defaultTeacherImg;
9955        }
9956
9957        // - set page meta information
9958        $this->set('headtext', $headTextWD);
9959        $this->set('title_for_layout', $pageTitleWD);
9960        //$this->set('meta_description', $metaDescWD);
9961        $this->set('meta_keywords',$teacher->name.',講師,オンライン英会話,ネイティブキャンプ');
9962        $this->set('counselingFlg',$teacher->counseling_flg);
9963        $this->set('meta_teacher_img',$_teacherImgUrl);
9964        //get own reviews
9965        $selfReviews = array();
9966        $selfLessonCount = 0;
9967        $daysPast = 0;
9968        if ($userId) {
9969            $selfReviews = $this->getUserReviews($userId, $teacherId);
9970            $userLessonDetail = $this->LessonOnairsLog->getUserLessonCount($userId, $teacherId);
9971            $selfLessonNow = $userLessonDetail['lessonCount'];
9972            $selfReservation = $userLessonDetail['reserveCount'];
9973            $selfLessonCount = $selfLessonNow + $selfReservation;
9974            $daysPast = $this->LessonOnairsLog->countDaysPast($userId, $teacherId);
9975        }
9976        //reservation and cancellation breakdown
9977        $reserveAndCancel = $this->getReserveAndCancelled($teacherId);
9978
9979        $options = $this->Auth->user('id') ? array('userId' => $this->Auth->user('id')) : array();
9980        $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir,true);
9981        $options['language_id'] = $reviewLanguage[0];
9982        $options['not_language_ids'] = $reviewLanguage[1] ?? null;
9983        $options['avatar'] = 1;
9984
9985        $userTable = new UserTable($this->Auth->user());
9986        $sapuriPlan = $userTable->isStudySapuri();
9987        $sapuriTextbookType = Configure::read('all_sapuri_textbook_category_types');
9988        if ($this->isStudySapuriUser && isset($sapuriTextbookType[$sapuriPlan])) {
9989            $options['textbook_category_type'] = $sapuriTextbookType[$sapuriPlan];
9990        } else {
9991            $options['textbook_category_type_not_in'] = $sapuriTextbookType;
9992        }
9993
9994        $reviews = $this->UsersClassEvaluation->getComments($teacherId, 0, 4, $options);
9995        $commentCount = $this->UsersClassEvaluation->getCommentCount($teacherId, $options);
9996        $approveFlag = $this->UsersClassEvaluation->getApproveEvalCount($teacherId);
9997
9998        # get weekly rating
9999        $approveFlag = $this->UsersClassEvaluation->getApproveEvalCount($teacherId);
10000
10001        $get_weekly_rating = $this->UsersClassEvaluation->getAvatarRatings($teacherId);
10002        
10003        /* -- NC-5293 start -- */
10004        $this->loadModel('Translation');
10005        $translationCategories = Configure::read('translation_categories');
10006        $translateParams = array(
10007            'languageCode' => $this->lang_iso,
10008            'categoryId' => $translationCategories['teacher_message'],
10009            'messageId' => $teacher->id,
10010            'text' => $teacher->message
10011        );
10012
10013        $translatedMessageParams = $translateParams;
10014        $translateParams['categoryId'] = $translationCategories['teacher_self_introduction_third_pp'];
10015        $translateParams['text'] = $teacher->self_introduction_third_pp;
10016        $translatedSelfIntroductionThirdPpParams = $translateParams;
10017        /* -- NC-5293 end -- */
10018
10019        // Translate and save translated data
10020        $globalTranslate = TeacherTable::translate(array(
10021            'id' => $teacherId,
10022            'lang'=> isset($this->localizeDir) ? $this->localizeDir : Configure::read('default.user_language'),
10023            'controller' => static::class
10024        ));
10025        $translatedMessageTranslation = isset($globalTranslate['message']) ? $globalTranslate['message'] : null;
10026        $translatedThirdppTranslation = isset($globalTranslate['self_introduction_third_pp']) ? $globalTranslate['self_introduction_third_pp'] : null;
10027        $this->set('message', $translatedMessageTranslation);
10028        $this->set('intro', $translatedThirdppTranslation);
10029
10030        //find the selfintro 
10031        $TeacherTable = new TeacherTable($teacher);
10032        $_userSelfIntro = $TeacherTable->iSNotDisplayHtmlTags($teacher->message);
10033        $_userSelfIntro = strip_tags($_userSelfIntro);
10034
10035        //set the new meta description
10036        $metaDescWD = TeacherTable::getMetaDescription2($_userSelfIntro);
10037        $this->set('meta_description', $metaDescWD);
10038    
10039        $favIds = $isFav ? [$teacher->id] : [];
10040        $teacherFavColor = $this->UsersFavoriteCategoriesTeacher->getColorFavTeacherByIds(['user_id' => $this->Auth->user('id'), 'teacher_ids' => $favIds]);
10041        $teacherFavsColors = $this->UsersFavoriteCategoriesTeacher->parseToHexColor([
10042            'favIds' => $favIds,
10043            'favIdsTeacherCategory' => $teacherFavColor
10044        ]);
10045        // set view vars
10046        $setData = array(
10047            'teacher' => $teacher,
10048            'onair' => $oOnair,
10049            'isFav' => $isFav,
10050            'teacherFavsColors' => $teacherFavsColors,
10051            'isHide' => $isHide,
10052            'favoriteCount' => $favoriteCount,
10053            'feature' => $feature,
10054            'tId' => $teacher->id,
10055            'user' => $user,
10056            'lessonAvailable' => isset($lessonAvailable['lessonAvailable']) ? $lessonAvailable['lessonAvailable'] : 0,
10057            'userMembership' => isset($userMembership)?$userMembership:'',
10058            'adminFlag' => isset($user['admin_flg'])?$user['admin_flg']:'0',
10059            'enquate6_options' => UserTable::getEnquate6(),
10060            'enquate7_options' => UserTable::getEnquate7(),
10061            'reviews' => $reviews,
10062            //'rates' => $rates,
10063            'approveEvalFlag' => $approveFlag,
10064            'weekly_ratings' => isset($get_weekly_rating) ? $get_weekly_rating['TeacherWeeklyRating'] : 0,
10065            'userId' => $userId,
10066            'cardAuth' => PaymentTable::checkIfCardAuth($this->Auth->user('id'), $this->Auth->user('hash16')),
10067            'teacherCoin' => empty($teacherCoin)? 0: (int)$teacherCoin,
10068            'callanCoin' => (int)$callanCoin,
10069            'teacherCallanDiscount' => empty($teacherCallanDiscount)? 0: $teacherCallanDiscount,
10070            'UserData' => $data,
10071            'userCountry' => $userCountry,
10072            'velifyCount' => $velifyCount,
10073            'firstTimeLoggedIn' => $firstTimeLoggedIn,
10074            //'rateBreakdown' => $rateBreakdown,
10075            'selfReviews' => $selfReviews,
10076            'selfLessonCount' => $selfLessonCount,
10077            'daysPast' => $daysPast,
10078            'reserveAndCancel' => $reserveAndCancel,
10079            'isLoggedIn' => $this->Auth->loggedIn(),
10080            'country' => $country,
10081            'timeDiff' => $timeDiff,
10082            'corporateId' => !empty($data['User']['corporate_id']) ? $data['User']['corporate_id'] : $this->Auth->user('corporate_id'),
10083            'translatedMessageParams' => $translatedMessageParams,
10084            'translatedSelfIntroductionThirdPpParams' => $translatedSelfIntroductionThirdPpParams,
10085            'translationModel' => $this->Translation,
10086            'hideLimitedPlanReservation' => $hideLimitedPlanReservation,
10087            'teacherCoinBeforeDiscount' => empty($teacherCoinBeforeDiscount)? 0: (int)$teacherCoinBeforeDiscount,
10088            'teacherCoinWithOp' => empty($teacherCoinWithOp)? 0: (int)$teacherCoinWithOp,
10089            'nativeOptionFlg' => $displayNativeOptionAmountFlg,
10090            'lessonCount' => $lessonCount,
10091        );
10092
10093        $this->set($setData);
10094        $this->set('avatar_teacher_detail', 1);
10095        if ($userId) {
10096            $points = $this->UsersPoint->find('first', array(
10097                'fields' => array('point'),
10098                    'conditions' => array(
10099                        'user_id' => $userId
10100                    )
10101                )
10102            );
10103
10104            $points = isset($points['UsersPoint']['point']) ? $points['UsersPoint']['point'] : 0;
10105            $reservePoint = Configure::read("reserve_point");
10106
10107            if (intval($reservePoint) < 1) $reservePoint = 0;
10108            //set promo discount for reservation
10109            // set paramater to 2 for reservation promo
10110            $bonus = CoinSetTable::getCoinSet(2);
10111            //check if the promo is valid today
10112            if ($bonus) {
10113                $reservePoint = $bonus;
10114            }
10115        } else {
10116            $points = 0;
10117        }
10118
10119        # get user timezone
10120        $user_timezone_id = (isset($this->sharedUserData['User']['timezone_id'])) ? $this->sharedUserData['User']['timezone_id'] : 203;
10121        $user_timezone_data = $this->Timezone->find('first',
10122            array(
10123                'fields' => array(
10124                    'Timezone.city_eng',
10125                    'Timezone.utc_offset',
10126                    'Timezone.country_code_id'
10127                ),
10128                'conditions' => array(
10129                    'Timezone.id' => $user_timezone_id
10130                ),
10131                'recursive' => -1
10132            )
10133        );
10134
10135        // - NJ-3653 get country
10136        $countryTimezone = null;
10137        if (!empty($user_timezone_data) && $user_timezone_data['Timezone']['country_code_id']) {
10138            // - Get all country Code
10139            $countryOptions = $this->Timezone->countryOptions();
10140
10141            $countryCodeId = $user_timezone_data['Timezone']['country_code_id'];
10142            $countryName = $countryOptions[$countryCodeId]['country_name'];
10143
10144            if (isset($countryName) && $countryName) {
10145                $countryTimezone = $countryName;
10146            }
10147        }
10148
10149
10150        $this->set('countryTimezone', $countryTimezone);
10151        $this->set('userTimezoneData', $user_timezone_data);
10152
10153        #user time
10154        $datetime = date('Y-m-d H:i:s');
10155        $localTime = $this->displayTime;
10156        // NJ-29496
10157        if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) { 
10158            $formattedDate = date('d/m/Y G:i', $localTime);
10159        } else {
10160            $formattedDate = date('Y/m/d G:i', $localTime);
10161        }
10162    
10163        $this->set('userCurrentTime', $formattedDate);        
10164
10165        $this->set('points', $points);
10166        $this->set('reservePoint', isset($reservePoint)? $reservePoint: 0);
10167
10168        $countrids_no = Configure::read('sms_send.countrids_no');
10169        $this->set('countrids_no', $countrids_no);
10170
10171        $deviceNotSupported = false;
10172        $ua = (!empty(myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']))) ? myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']) : '';
10173        if (strpos($ua, 'Android') !== false || strpos($ua, 'iPhone') !== false || strpos($ua, 'iPad') !== false || strpos($ua, 'iPod') !== false) {
10174            $deviceNotSupported = true;
10175        }
10176        $this->set('deviceNotSupported', $deviceNotSupported);
10177
10178        $this->set('statusCheck', array(1, 4));
10179
10180        $this->set('login', $this->Auth->loggedIn());
10181
10182        //get preset textbook -> last viewed -> default textbook category first lesson
10183        $presetParams = array("user_id" => $this->Auth->User('id'));
10184
10185        //add additional parameters
10186        if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))) {
10187            $presetParams["lang"] = $this->localizeDir;
10188        }
10189        //NC-8728 check if user is valid for Study Sapuri Business English Daily textbooks
10190        $presetParams["userValidForSSBEDT"] = $this->userValidForSSBEDT();
10191
10192        #NC-9916
10193        if($data['User']) {
10194            $presetParams['native_language2'] = $userData->native_language2;
10195            $presetParams["userMembershipType"] = $userData->getMembershipTypeIndex();
10196        }
10197        $preset_data = $this->UsersTextbookInfo->getPreset($presetParams);
10198
10199        if(isset($preset_data['preset_connect_id']) && !empty($preset_data['preset_connect_id'])) {
10200            # for preset
10201            $presetParams['connect_id'] = $preset_data['preset_connect_id'];
10202            $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
10203
10204        } else if(isset($preset_data['last_viewed_connect_id']) && !empty($preset_data['last_viewed_connect_id'])) {
10205            # use last viewed textbook if no preset data.
10206            $presetParams['connect_id'] = $preset_data['last_viewed_connect_id'];
10207            $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
10208
10209        }
10210
10211        // - NJ-3878 : add trapping for pc and app(api) 1 = pc 0 = app
10212        $presetParams['is_pc_flg'] = 1;
10213
10214        # fetch preset
10215        $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
10216        if(!$preset) {
10217            unset($presetParams['connect_id']);
10218            unset($presetParams['last_opened_date']);
10219            $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
10220        }
10221
10222        // NC-8020
10223        $this->set('textbookConnectId', $preset['textbook_connect_id']);
10224        $this->set('textbookCategoryTypeId', $preset['textbook_type']);
10225
10226        //set variable preset textbook to be displayed
10227        $this->set('preset', $preset);
10228        // apology list (cancellation of reservation)
10229         $apologyList = array(); // NC-4749 : hide list, used function from model and made it popup modal
10230        $this->set('apologyList', $apologyList);
10231
10232        $getAvatarParams = array(
10233            "avatar_id" => $teacherId,
10234            "user_id" => $this->Auth->user('id'),
10235            "stealth_flg" => $this->Cookie->read('stealth.setting')
10236        );
10237        $avatarTeacherIds = $this->Teacher->getAvatarTeacherId($getAvatarParams);
10238
10239        // NJ-18780 : check if user is normal lite plan
10240        $_paymentPlanID = isset($this->sharedUserData['User']['payment_plan_id']) ? $this->sharedUserData['User']['payment_plan_id'] : null;
10241        $isNormalLitePlanUser = (in_array($_paymentPlanID, Configure::read('lite_payment_plans') ) ) ? true : false;
10242
10243
10244        $disabledSchedule = $this->LessonSchedule->getDisabledDaysPC(array(
10245            'userId' => $this->Auth->user('id'),
10246            'teacherId' => $avatarTeacherIds,
10247            'timeDiff' => $this->timeDiff,
10248            'isNormalLitePlanUser' => $isNormalLitePlanUser
10249        ));
10250
10251        // dynamic techer
10252
10253        $avatarParams = array(
10254            "user_id" => $this->Auth->user('id'),
10255            "avatar_id" => $teacherId
10256        );
10257
10258        $avatarTeacherArr = $this->Avatar->availableTeacher($avatarParams);
10259        $lessTime = 0;
10260        if ( isset($avatarTeacherArr["teacher_id"]) ) {
10261            $avatarTeacherId = $avatarTeacherArr["teacher_id"];
10262        }
10263        if ( isset($avatarTeacherArr["less_time"]) ) {
10264            $lessTime = $avatarTeacherArr["less_time"];
10265        }
10266        $options['isAvatar'] = 1;
10267        $reviewsCount = $this->UsersClassEvaluation->getCommentCount($teacherId, $options);
10268
10269        $this->set('order', $this->Cookie->read('teacherReviewOrder') ?? 0);
10270        $this->set('reviewsCount', $reviewsCount);
10271        $this->set('teacherName', $teacherName);
10272        $this->set('teacherImageSrc', $teacherImageSrc);
10273        $this->set('lessTime', $lessTime);
10274        $this->set('isAvatar',true);
10275        $this->set('avatarTeacherId', $avatarTeacherId);
10276        $this->set('disabledSchedule', json_encode($disabledSchedule));
10277        $this->set('showNoticeMaxLimit', (isset($disabledSchedule['disableAll']) ? $disabledSchedule['disableAll'] : false));
10278        $this->set('noIndexFlgOveride', ($this->localizeDir != Configure::read('default.user_language') ? true : false));
10279
10280        // - NJ-6390 add highLightFlag
10281        $this->set('highLightFlag', isset($highLightFlag) && $highLightFlag? $highLightFlag: null);
10282
10283        // class evaluation
10284        if ($this->request->query('chatHash')) {
10285            $chatHash = $this->request->query('chatHash');
10286
10287            // Check if chatHash is valid
10288            $this->LessonOnairsLog->openDBReplica();
10289            $allData = $this->LessonOnairsLog->find('first', $this->checkHash('LessonOnairsLog',$chatHash));
10290            $this->LessonOnairsLog->closeDBReplica();
10291
10292            if(!$allData) { // if LessonOnairsLog's chat_hash returns null/empty , retrieve record from lessonOnair
10293                $this->LessonOnair->openDBReplica();
10294                $allData = $this->LessonOnair->find('first', $this->checkHash('LessonOnair',$chatHash));
10295                $this->LessonOnair->closeDBReplica();
10296
10297                if(!$allData) {
10298                    return $this->redirect(array('controller' => 'home', 'action' => 'index', 'home'));
10299                }
10300            }
10301
10302            $userValidForSSBEDT = false;
10303            if (isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')){
10304                $userValidForSSBEDT = true;
10305            }
10306            $param = array(
10307                "user_id" => $userId,
10308                "select_method" => "first",
10309                "env_flag" => "all",
10310                'connect_id' => $allData['Connect']['id'],
10311                "user_locale" => $this->localizeDir,
10312                "userValidForSSBEDT" => $userValidForSSBEDT
10313            );
10314            
10315            if ($userId && isset($allData['Connect']['category_id']) && $allData['Connect']['category_id']) {
10316                $corporateParams = array('user_id' => $userId);
10317                $corporateTextbookControlFlg = $this->Corporate->getCorporateTextbookControl($corporateParams);
10318                
10319                if ($corporateTextbookControlFlg == 1) {
10320                    $categoryData = $this->TextbookCategory->getKidsCategoryTypesById($allData['Connect']['category_id']);
10321                    if (!empty($categoryData)) {
10322                        $param['include_kids_category'] = $allData['Connect']['category_id'];
10323                    }
10324                }
10325            }
10326            $textbookData = $this->Textbook->getTextbooks($param);
10327            $data = $textbookData['res_data'];
10328
10329            $isReservedLesson = 2;
10330            $hideTextbookChangeModal = $enableNextTextbookChapterButton = 'false';
10331            $latestPresetTextbookConnect_id = (int)$data['TextbookConnect']['id'];
10332            $latestPresetTextbookConnect_categoryId = (int)$data['TextbookConnect']['category_id'];
10333            $latestPresetTextbookConnect_subCategoryId = (int)$data['TextbookConnect']['subcategory_id'];
10334            $latestPresetTextbookCategory_textbookCatType = (int)$data['TextbookCategory']['textbook_category_type'];
10335
10336            //Optimize PC /lesson-finish page
10337            $lessonOnairLatestData = $this->LessonOnair->getLatestLessonOnairDetailsOfUserAndTeacher($userId, $teacherId);
10338            if(isset($lessonOnairLatestData) && $lessonOnairLatestData) {
10339                $lessonOnairLatestDataFlg = true;
10340                $lessonOnairLatest_connectId = (int)$lessonOnairLatestData['LessonOnair']['connect_id'];
10341                $lessonOnairLatest_lessonType = (int)$lessonOnairLatestData['LessonOnair']['lesson_type'];
10342            } else {
10343                $lessonOnairLogsLatestData = $this->LessonOnairsLog->getLatestLessonLogsDetailsOfUserAndTeacher($userId, $teacherId);
10344                if(isset($lessonOnairLogsLatestData) && $lessonOnairLogsLatestData) {
10345                    $lessonOnairLogsLatest_connectId = (int)$lessonOnairLogsLatestData['LessonOnairsLog']['connect_id'];
10346                    $lessonOnairLogsLatest_lessonType = (int)$lessonOnairLogsLatestData['LessonOnairsLog']['lesson_type'];
10347                }
10348            }
10349
10350            // - initialize empty variable
10351            $isLatestPresetTextbookMadeDuringLastLesson = [];
10352            $latestPresetTextbookParams = [];
10353
10354            // For hiding of textbookchange modal (if reserved lesson & not studySapuri)
10355            if ($lessonOnairLatestDataFlg) {
10356                $latestPresetTextbookParams = array (
10357                    'userId' => $userId,
10358                    'latestPresetTextbookConnect_id' => $latestPresetTextbookConnect_id,
10359                    'lessonOnairLatest_startTime' => $lessonOnairLatestData['LessonOnair']['start_time'],
10360                    'lessonOnairLatest_endTime' => $lessonOnairLatestData['LessonOnair']['end_time']
10361                );
10362
10363            // - if has lesson onairs log
10364            } else if ($lessonOnairLogsLatestData) {
10365                $latestPresetTextbookParams = array (
10366                    'userId' => $userId,
10367                    'latestPresetTextbookConnect_id' => $latestPresetTextbookConnect_id,
10368                    'lessonOnairLogsLatest_startTime' => $lessonOnairLogsLatestData['LessonOnairsLog']['start_time'],
10369                    'lessonOnairLogsLatest_endTime' => $lessonOnairLogsLatestData['LessonOnairsLog']['end_time']
10370                );
10371
10372            }
10373            
10374            // - if has parameters for fetching latest textbook parameters
10375            if ($latestPresetTextbookParams) {
10376                $isLatestPresetTextbookMadeDuringLastLesson = $this->UsersTextbookInfo->checkLatestUserTextbookInfoChangedDuringLesson($latestPresetTextbookParams);
10377            }
10378
10379            // -  check sapuri ID
10380            if(!isset($this->studySapuriId) || !$this->studySapuriId) {
10381                if (isset($lessonOnairLatestDataFlg)) {
10382                    if (is_array($isLatestPresetTextbookMadeDuringLastLesson) && !empty($isLatestPresetTextbookMadeDuringLastLesson)
10383                        && $latestPresetTextbookConnect_id == $lessonOnairLatest_connectId && $lessonOnairLatest_lessonType == $isReservedLesson
10384                    ) {
10385                        $hideTextbookChangeModal = 'true';
10386                    }
10387                } else {
10388                    if (
10389                        is_array($isLatestPresetTextbookMadeDuringLastLesson) && !empty($isLatestPresetTextbookMadeDuringLastLesson)
10390                        && $latestPresetTextbookConnect_id == $lessonOnairLogsLatest_connectId &&  $lessonOnairLogsLatest_lessonType == $isReservedLesson
10391                    ) {
10392                        $hideTextbookChangeModal = 'true';
10393                    }
10394                }
10395            }
10396
10397            $onGoingLesson = $this->LessonOnair->hasOngoingLesson($this->Auth->user('id'));
10398
10399            // For enabling next textbook chapter button (if not callan and not ongoing lesson)
10400            if (
10401                $hideTextbookChangeModal == 'false'
10402                && (isset($latestPresetTextbookCategory_textbookCatType) &&  !in_array($latestPresetTextbookCategory_textbookCatType, Configure::read('callan_textbook_type')))
10403                && (isset($onGoingLesson) && $onGoingLesson == false)
10404            ) {
10405                $allTextbookParams = array(
10406                    'category_id' => $latestPresetTextbookConnect_categoryId, 
10407                    'connect_id' => $latestPresetTextbookConnect_id,
10408                    'subcategory_id' => $latestPresetTextbookConnect_subCategoryId
10409                );
10410                
10411                $allTextbookChapters = $this->TextbookConnect->getTextbookPrevAndNextFunction($allTextbookParams);
10412                // if has next textbook chapter, show button 
10413                if (
10414                    is_array($allTextbookChapters) && !is_null($allTextbookChapters) 
10415                    && ($allTextbookChapters['next'] !== '' && !is_null($allTextbookChapters['next']))
10416                ) {
10417                    $enableNextTextbookChapterButton = 'true';
10418                }
10419            }
10420
10421            $this->set('enableNextTextbookChapterButton', $enableNextTextbookChapterButton);
10422
10423            if(!empty($this->sharedUserData['User'])){
10424                // - campaing stamps
10425                $this->getActiveCampaignStampData();
10426            }
10427
10428            $this->set('chatHash', $chatHash);
10429        }
10430
10431        //NJ-33414
10432        $this->UsersDetail->openDBReplica();
10433        $fetchUsersDetail = $this->UsersDetail->find('first', array(
10434            'fields' => array(
10435                'lesson_request_flg'
10436            ),
10437            'conditions' =>  array('user_id' => $this->sharedUserData['User']['id']),
10438            'recursive' => -1
10439        ));
10440        $this->UsersDetail->closeDBReplica();
10441
10442        $lessonRequestFlg = $fetchUsersDetail ? $fetchUsersDetail['UsersDetail']['lesson_request_flg'] : 1;
10443        $this->set('lessonRequestFlg',$lessonRequestFlg);
10444
10445        //-- NJ-44869 skip communication modal
10446        $lessonSystemTroubleFlg = 0;
10447        $hideConnectionModalFlg = 0;
10448
10449        // if (!empty($chatHash)) {
10450        //     $memcached = new myMemcached();
10451        //     $lessonSystemTroubleCache = $memcached->get('lesson_system_trouble_' . $chatHash);
10452        //     $lessonDisconnectionChatHash = $memcached->get('lesson_disconnection_flag_' . $teacherId);
10453            
10454        //     $hideConnectionModalFlg = $memcached->get('hide_connection_modal_flg_'.$teacherId.'-'.$chatHash);
10455
10456        //     if (!empty($lessonSystemTroubleCache)) {
10457        //         $memcached->delete('lesson_system_trouble_' . $chatHash);
10458        //         $lessonSystemTroubleFlg = 1;
10459        //     } elseif (!empty($lessonDisconnectionChatHash) && $lessonDisconnectionChatHash == $chatHash) {
10460        //         $lessonSystemTroubleFlg = 1;
10461        //     }
10462        // }
10463
10464        $this->set('lessonSystemTroubleCache', $lessonSystemTroubleFlg);
10465        $this->set('hideConnectionModalFlg', $hideConnectionModalFlg);
10466    }
10467
10468    /**
10469     * @api {get} /user/waiting/getTeacherReviews getTeacherReviews()
10470     * @apiName getTeacherReviews
10471     * @apiGroup Waiting
10472     * @apiDescription Retrieves the reviews for a specific teacher in Native Camp. It checks if the request is an AJAX request and returns the reviews data.
10473     *
10474     * @apiBody {String} [teacherId] The ID of the teacher.
10475     * @apiBody {Boolean} [isCounseling] Indicates whether the request is for a counseling teacher.
10476     * @apiBody {Boolean} [isAvatar] Indicates whether the request is for an avatar teacher.
10477     * @apiBody {Boolean} [isCustomerSupport] Indicates whether the request is for a customer support teacher.
10478     * @apiBody {Number} [order] The order of the reviews.
10479     * @apiBody {Number} [limit=4] The limit of reviews to retrieve.
10480     * @apiBody {Number} [page=1] The current page number.
10481     * @apiBody {Number} [rate] The rating filter for the reviews.
10482     * @apiBody {String} [textbook_course] The textbook course filter for the reviews.
10483     * @apiBody {String} [textbook_series] The textbook series filter for the reviews.
10484     * @apiBody {String} [textbook_preset] The textbook preset filter for the reviews.
10485     * @apiBody {String} [textbook_favorite] The textbook favorite filter for the reviews.
10486     * @apiBody {Boolean} [load_categories] Indicates whether to load the textbook categories.
10487     * @apiBody {Boolean} [load_paging] Indicates whether to load the paging data.
10488     * 
10489     * @apiSuccess {String} htmlReviews The HTML content for the reviews.
10490     * @apiSuccess {Number} counselorReviewsCount The count of counselor reviews.
10491     * @apiSuccess {String} htmlPaging The HTML content for the paging data.
10492     * @apiSuccess {Object[]} textbookCategories The textbook categories data.
10493     * @apiSuccess {String} textbookCategories.id The ID of the textbook category.
10494     * @apiSuccess {String} textbookCategories.name The name of the textbook category.
10495     * @apiSuccess {String} textbookCategories.image The image URL of the textbook category.
10496     *
10497     * @apiSuccessExample {json} Success-Response:
10498     *     {
10499     *         "htmlReviews": "<div>Reviews HTML</div>",
10500     *         "counselorReviewsCount": 10,
10501     *         "htmlPaging": "<div>Paging HTML</div>",
10502     *         "textbookCategories": [
10503     *             {
10504     *                 "id": "1",
10505     *                 "name": "Category Name",
10506     *                 "image": "http://example.com/image.jpg"
10507     *             },
10508     *             ...
10509     *         ]
10510     *     }
10511     *
10512     * @apiError {String} error Message indicating the error.
10513     *
10514     * @apiErrorExample {json} Error-Response:
10515     *     {
10516     *         "error": "Invalid request."
10517     *     }
10518     * 
10519     * @apiSampleRequest off
10520     */
10521    public function getTeacherReviews() {
10522        $this->autoRender = $this->layout = false;
10523        $get = $this->request->query;
10524
10525        if (isset($get['teacherId']) && !filter_var($get['teacherId'], FILTER_VALIDATE_INT)) {
10526            return json_encode([]);
10527        }
10528
10529        $counselorReviewsCount = 0;
10530        if (isset($get['teacherId']) || isset($get['isCounseling']) || isset($get['isAvatar']) || isset($get['isCustomerSupport'])) {
10531            if (isset($get['order'])) {
10532                $this->Cookie->write('teacherReviewOrder', $get['order'], true, 0);
10533            }
10534            $order = $this->Cookie->read('teacherReviewOrder') ?? 0;
10535            $limit = !empty($get['limit']) && is_numeric($get['limit']) ? (int) $get['limit'] : 4;
10536            $page  = !empty($get['page'])  && is_numeric($get['page'])  ? (int) $get['page']  : 1;
10537            $params = array(
10538                'order' => $order,
10539                'limit' => $limit,
10540                'offset' => ($page - 1) * $limit,
10541                'userId' => $this->Auth->user('id') ? $this->Auth->user('id') : '',
10542                'nc_terminal_type' => Configure::read('nc_terminal_type.pc'),
10543                'lang' => $this->localizeDir
10544            );
10545
10546            // office teacher
10547            if ( isset($get['isCounseling']) || isset($get['isCustomerSupport']) ) {
10548                myTools::initializeApiTunnel(array('TeachersCounselorReviewsController'));
10549                $teachersReviews = new TeachersCounselorReviewsController();
10550                $teachersReviews->params = $params;
10551                $isCustomerSupport = isset($get['isCustomerSupport']) ? true : false;
10552                $reviews = $teachersReviews->getAllCounselEvaluation($isCustomerSupport);
10553                $counselorReviewsCount = $teachersReviews->getCountAllEvaluation($isCustomerSupport);
10554            } else {
10555                myTools::initializeApiTunnel(array('TeachersReviewsController'));
10556                $teachersReviews = new TeachersReviewsController();
10557                $params['conditions'] = array();
10558                if(isset($get['isAvatar'])) {
10559                    if(!isset($get['load_categories'])) {
10560                        $params['conditions'][] = "UsersClassEvaluation.teacher_id IN (SELECT id FROM teachers WHERE avatar_id = {$get['teacherId']} AND status = 1)";
10561                        $params['conditions'][] = "UsersClassEvaluation.approve_flag = 1";
10562                        $params['conditions'][] = "UsersClassEvaluation.user_comment <> ''";
10563                    }
10564                    $params['isAvatar'] = true;
10565                    $params['avatarTeacherId'] = $get['teacherId'];
10566                } else {
10567                    $params['conditions']['UsersClassEvaluation.teacher_id'] = $get['teacherId'];
10568                }
10569
10570                $params['rate'] = $get['rate'] ?? null;
10571                $params['textbook_course'] = $get['textbook_course'] ?? null;
10572                $params['textbook_series'] = $get['textbook_series'] ?? null;
10573                $params['textbook_preset'] = $get['textbook_preset'] ?? null;
10574                $params['textbook_favorite'] = $get['textbook_favorite'] ?? null;
10575                $params['is_sapuri_user'] = $this->isStudySapuriUser ? true : false;
10576
10577
10578                $userTable = new UserTable($this->Auth->user());
10579                $sapuriPlan = $userTable->isStudySapuri();
10580                $sapuriTextbookType = Configure::read('all_sapuri_textbook_category_types');
10581                if ($this->isStudySapuriUser && isset($sapuriTextbookType[$sapuriPlan])) {
10582                    $params['textbook_category_type'] = $sapuriTextbookType[$sapuriPlan];
10583                } else {
10584                    $params['textbook_category_type_not_in'] = $sapuriTextbookType;
10585                }
10586
10587                if ($userId = $this->Auth->user('id')) {
10588                    $corporateParams = array('user_id' => $userId);
10589                    $corporateTextbookControlFlg = $this->Corporate->getCorporateTextbookControl($corporateParams);
10590                    
10591                    if ($corporateTextbookControlFlg == 1) {
10592                        $params['textbook_category_type_not_in'] = Configure::read('kids_callan_kids_textbook_category_types');
10593                    }
10594                }
10595
10596                $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir, true);
10597                $params['build_conditions']['language_id'] = $reviewLanguage[0];
10598                $params['build_conditions']['not_language_ids'] = $reviewLanguage[1] ?? null;
10599                
10600                $teachersReviews->params = $params;
10601                $reviews = $teachersReviews->getReviews();
10602
10603                if (isset($get['load_categories'])) {
10604                    $teachersReviews->params['load_favorite'] = true;
10605                    $teachersReviews->params['isLoadCategories'] = true;
10606                    $textbookCategories = $teachersReviews->getReviewTextbooks($this->sharedUserData['User'], $this->localizeDir);
10607                }
10608            }
10609            if ($reviews) {
10610                $view = new View($this, false);
10611                $htmlReviews = $view->element('teacherReviews', array('reviews' => $reviews));
10612
10613                if (isset($get['load_paging'])) {
10614                    $commentCount = $this->UsersClassEvaluation->useReplica()->countTeacherReviews($teachersReviews->convertOldParams($params), true);
10615                    $paging = myTools::paging($page, $commentCount, $limit);
10616                    $htmlPaging = $view->element('pager_link_instructor_reviews_ng', ['paging' => $paging, 'order' => $order]);
10617                }
10618            }
10619        }
10620
10621        $returnArr = array();
10622        if (isset($htmlReviews)) {
10623            $returnArr['htmlReviews'] = $htmlReviews;
10624            $returnArr['counselorReviewsCount'] = $counselorReviewsCount;
10625        }
10626        if (isset($htmlPaging)) {
10627            $returnArr['htmlPaging'] = $htmlPaging;
10628        }
10629        if(isset($textbookCategories)) {
10630            $returnArr['textbookCategories'] = $textbookCategories;
10631        }
10632
10633        return json_encode($returnArr);
10634    }
10635
10636    /**
10637     * @api {post} /user/waiting/favoriteTextbookCategoryForReview favoriteTextbookCategoryForReview()
10638     * @apiName favoriteTextbookCategoryForReview
10639     * @apiGroup Waiting
10640     * @apiDescription Retrieves the favorite textbook categories for review for the authenticated user in Native Camp. It returns the favorite textbook categories data.
10641     *
10642     * @apiBody {String} [lang=ja] The language code for the request.
10643     * @apiBody {Boolean} [isAvatar] Indicates whether the request is for an avatar teacher.
10644     * @apiBody {String} [teacherId] The ID of the teacher.
10645     * 
10646     * @apiSuccess {Object[]} favorite The favorite textbook categories data.
10647     * @apiSuccess {String} favorite.id The ID of the textbook category.
10648     * @apiSuccess {String} favorite.name The name of the textbook category.
10649     * @apiSuccess {String} favorite.image The image URL of the textbook category.
10650     *
10651     * @apiSuccessExample {json} Success-Response:
10652     *     {
10653     *         "favorite": [
10654     *             {
10655     *                 "id": "1",
10656     *                 "name": "Category Name",
10657     *                 "image": "http://example.com/image.jpg"
10658     *             },
10659     *             ...
10660     *         ]
10661     *     }
10662     *
10663     * @apiError {String} error Message indicating the error.
10664     *
10665     * @apiErrorExample {json} Error-Response:
10666     *     {
10667     *         "error": "Invalid request."
10668     *     }
10669     * 
10670     * @apiSampleRequest off
10671     */
10672    public function favoriteTextbookCategoryForReview() {
10673        $this->autoRender = false;
10674        $result = [];
10675        if (isset($this->request->data) ) {
10676            $inputs = $this->request->data;
10677            $lang = 'ja';
10678            if (isset($inputs['lang']) && !empty($inputs['lang'])) $lang = $inputs['lang'];
10679            $this->localizeDir = $lang;
10680
10681            myTools::initializeApiTunnel(array('TeachersReviewsController'));
10682            $teachersReviews = new TeachersReviewsController();
10683            $params = array(
10684                'userId' => $this->Auth->user('id') ? $this->Auth->user('id') : '',
10685                'nc_terminal_type' => Configure::read('nc_terminal_type.pc'),
10686                'lang' => $this->localizeDir
10687            );
10688            $params['conditions'] = array();
10689
10690            if( isset($inputs['isAvatar']) && $inputs['isAvatar'] ) {
10691                $params['isAvatar'] = true;
10692                $params['isLoadCategories'] = true;
10693            } else {
10694                $params['conditions']['UsersClassEvaluation.approve_flag'] = 1;
10695                $params['conditions']['UsersClassEvaluation.user_comment <>'] = '';
10696                $params['conditions']['UsersClassEvaluation.teacher_id'] = $inputs['teacherId'];
10697            }
10698            $params['is_sapuri_user'] = $this->isStudySapuriUser ? true : false;
10699
10700            $userTable = new UserTable($this->Auth->user());
10701            $sapuriPlan = $userTable->isStudySapuri();
10702            $sapuriTextbookType = Configure::read('all_sapuri_textbook_category_types');
10703
10704            if ($this->isStudySapuriUser && isset($sapuriTextbookType[$sapuriPlan])) {
10705                $params['textbook_category_type'] = $sapuriTextbookType[$sapuriPlan];
10706            } else {
10707                $params['textbook_category_type_not_in'] = $sapuriTextbookType;
10708            }
10709
10710            if ($userId = $this->Auth->user('id')) {
10711                $corporateTextbookControlFlg = $this->Corporate->getCorporateTextbookControl(['user_id' => $userId]);
10712                if ($corporateTextbookControlFlg == 1) {
10713                    $params['textbook_category_type_not_in'] = Configure::read('kids_callan_kids_textbook_category_types');
10714                }
10715            }
10716
10717            $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir, true);
10718            $params['build_conditions']['language_id'] = $reviewLanguage[0];
10719            $params['build_conditions']['not_language_ids'] = $reviewLanguage[1] ?? null;
10720            $params['load_favorite'] = true;
10721            $teachersReviews->params = $params;
10722
10723            $textbookCategories = $teachersReviews->getReviewTextbooks($this->sharedUserData['User'], $this->localizeDir);
10724            $result = !empty($textbookCategories) && isset($textbookCategories['favorite']) ? $textbookCategories['favorite'] : [];
10725        }
10726        return json_encode($result);
10727    }
10728
10729    /**
10730     * @api {post} /user/waiting/teacherAvatarStatus teacherAvatarStatus()
10731     * @apiName teacherAvatarStatus
10732     * @apiGroup Waiting
10733     * @apiDescription Retrieves the status of avatar teachers for the authenticated user in Native Camp. It checks the availability of the specified avatar teachers and returns their status.
10734     *
10735     * @apiBody {String[]} avatar_id_array The array of avatar teacher IDs.
10736     * 
10737     * @apiSuccess {Object} result The status of the avatar teachers.
10738     * @apiSuccess {Object} result.avatarId The status data for the avatar teacher.
10739     * @apiSuccess {Boolean} result.avatarId.available Indicates whether the avatar teacher is available.
10740     * @apiSuccess {String} result.avatarId.status The status of the avatar teacher.
10741     *
10742     * @apiSuccessExample {json} Success-Response:
10743     *     {
10744     *         "123": {
10745     *             "available": true,
10746     *             "status": "online"
10747     *         },
10748     *         "456": {
10749     *             "available": false,
10750     *             "status": "offline"
10751     *         }
10752     *     }
10753     *
10754     * @apiError {String} error Message indicating the error.
10755     *
10756     * @apiErrorExample {json} Error-Response:
10757     *     {
10758     *         "error": "Invalid request."
10759     *     }
10760     * 
10761     * @apiSampleRequest off
10762     */
10763    public function teacherAvatarStatus() {
10764        $this->autoRender = $this->layout = false;
10765        $userId = $this->Auth->user('id') ? $this->Auth->user('id') : '';
10766        $post = $this->request->data;
10767        $avatarIdArr = array_flip(Configure::read("default_avatar_detail"));
10768        $result = array();
10769
10770        if(isset($post["avatar_id_array"]) && is_array($post["avatar_id_array"]) ) {
10771            foreach ($post["avatar_id_array"] as $key => $avatarId) {
10772
10773                    $params = array(
10774                        "user_id" => $userId,
10775                        "avatar_id" => $avatarId
10776                    );
10777                    $data = $this->Avatar->availableTeacher($params);
10778                    $result[$avatarId] = $data;
10779
10780
10781            }
10782
10783        }
10784
10785        return json_encode($result);
10786
10787    }
10788
10789    /**
10790     * @api {get} /user/waiting/checkMaintenanceForAlert checkMaintenanceForAlert()
10791     * @apiName checkMaintenanceForAlert
10792     * @apiGroup Waiting
10793     * @apiDescription Checks if there is an upcoming maintenance period and returns an alert message if maintenance is scheduled.
10794     *
10795     * @apiSuccess {Number} is_maintenance Indicates whether maintenance is scheduled (0: No, 1: Yes).
10796     * @apiSuccess {String} message The maintenance alert message.
10797     * @apiSuccess {Number} [timezone_id] The ID of the user's timezone (if applicable).
10798     *
10799     * @apiSuccessExample {json} Success-Response:
10800     *     {
10801     *         "is_maintenance": 1,
10802     *         "message": "2:00AMより定期メンテナンスを行います。レッスンは、2:00AMに終了しますのでご了承ください。",
10803     *         "timezone_id": 1
10804     *     }
10805     *
10806     * @apiError {String} error Message indicating the error.
10807     *
10808     * @apiErrorExample {json} Error-Response:
10809     *     {
10810     *         "error": "Invalid request."
10811     *     }
10812     * 
10813     * @apiSampleRequest off
10814     */
10815    public function checkMaintenanceForAlert() {
10816        $this->autoRender = $this->layout = false;
10817        $response = array(
10818            'is_maintenance' => 0,
10819            'message' => __d('waiting','2:00AMより定期メンテナンスを行います。レッスンは、2:00AMに終了しますのでご了承ください。')
10820        );
10821        if (!myTools::checkCompanyIP($_SERVER['REMOTE_ADDR'])) {
10822            $conditions = array(
10823                'is_active' => 1,
10824                'start_date <= DATE_ADD(NOW(), INTERVAL 26 MINUTE)',
10825                'end_date >= NOW()'
10826            );
10827            $maintenanceModel = ClassRegistry::init('Maintenance');
10828            $maintenanceModel->openDBReplica();
10829            $maintenance = $maintenanceModel->find('first',array(
10830                'conditions' => $conditions
10831            ));
10832            $maintenanceModel->closeDBReplica();
10833            if ($maintenance) {
10834                $response['is_maintenance'] = 1;
10835                # maintenance time on user side
10836                if ($this->sharedUserData['User']['timezone_id']) {
10837                    $response['timezone_id'] = $this->sharedUserData['User']['timezone_id'];
10838                    $timezones = $this->Timezone->getFormattedRecruitTimezones();
10839                    $userTimeZoneData = $timezones[$this->sharedUserData['User']['timezone_id']];
10840                    $datetime = date($maintenance['Maintenance']['start_date']); // maintenance time
10841                    $timestamp = strtotime($datetime);
10842                    $fromTime = $timestamp + (($userTimeZoneData['jp_time_diff'] / 60) * 60 * 60);
10843                    $userMaintenanceTime = date("g:iA", $fromTime);
10844                    $uData = $this->Timezone->getTimezoneUserData($this->sharedUserData['User']['timezone_id']);
10845                    $alertMessageTime = $userMaintenanceTime. " (UTC".$uData['Timezone']['utc_offset'].") " .$userTimeZoneData['data-timezone_name'];
10846                    $alertMessage = sprintf(__d('waiting','%s より定期メンテナンスを行います。時間になりましたらレッスンも終了しますのでご了承ください。'), $alertMessageTime);
10847                    $response['message'] = $alertMessage;
10848                }
10849            }
10850        }
10851        echo json_encode($response);
10852    }
10853
10854    private function isAvatar($teacherID=null){
10855        $result = null;
10856        if ($teacherID) {
10857            $get = $this->Teacher->useReplica()->find('first',array(
10858                    'conditions' => array( 'Teacher.id' => $teacherID ),
10859                    'fields' => array(
10860                        'Teacher.id',
10861                        'Teacher.avatar_id',
10862                        'Teacher.avatar_parent_flg',
10863                        'Teacher.avatar_flg'
10864                    ),
10865                    'recursive' => -1
10866                )
10867            );
10868            if ($get) {
10869                // check parent
10870                $avatarParent = isset($get['Teacher']['avatar_parent_flg']) && $get['Teacher']['avatar_parent_flg'] ? $get['Teacher']['avatar_parent_flg'] : 0;
10871                $avatar = isset($get['Teacher']['avatar_flg']) && $get['Teacher']['avatar_flg'] ? $get['Teacher']['avatar_flg'] : 0;
10872                $avatarId = isset($get['Teacher']['avatar_id']) && $get['Teacher']['avatar_id'] ? $get['Teacher']['avatar_id'] : 0;
10873
10874                if ( ( $avatar && $avatarId ) || $avatarParent ) {
10875                    if ( $avatar && $avatarId ) {
10876                        $result = $avatarId;
10877                    }
10878                    if ($avatarParent) {
10879                        $result = $teacherID;
10880                    }
10881                }
10882            }
10883        }
10884        return $result;
10885    }
10886
10887
10888
10889    //Retrieves the latest lesson history for a specific user with counselor teachers in Native Camp. It returns the lesson history data.
10890    public function counselorLatestLessonHistory($userId){
10891
10892        $memcache = new myMemcached();
10893        $textbookNamesCachedArr = $memcache->get(Configure::read('textbook_names_cache_key'));
10894
10895        $counselorTeacherId =  Configure::read('default_counselor_detail');
10896        //NC-7984
10897        $lessonHistoryJoins = array(
10898            "use index (user_id)",
10899            array(
10900                'type' => 'LEFT',
10901                'table' => 'users_class_evaluations',
10902                'alias' => 'usersClassEvaluations',
10903                'conditions' => array('usersClassEvaluations.chat_hash = LessonOnairsLog.chat_hash')
10904            ),
10905            array(
10906                'type' => 'LEFT',
10907                'table' => 'textbook_connects',
10908                'alias' => 'TextbookConnect',
10909                'conditions' => 'LessonOnairsLog.connect_id = TextbookConnect.id'
10910            ),
10911            array(
10912                'type' => 'LEFT',
10913                'table' => 'textbook_categories',
10914                'alias' => 'TextbookCategory',
10915                'conditions' => 'TextbookConnect.category_id = TextbookCategory.id'
10916            ),
10917            array(
10918                'type' => 'LEFT',
10919                'table' => 'textbook_subcategories',
10920                'alias' => 'TextbookSubategory',
10921                'conditions' => 'TextbookConnect.subcategory_id = TextbookSubategory.id'
10922            ),
10923            array(
10924                'type' => 'LEFT',
10925                'table' => 'textbooks',
10926                'alias' => 'Textbook',
10927                'conditions' => 'Textbook.id = TextbookConnect.textbook_id'
10928            ),
10929            array(
10930                'type' => 'LEFT',
10931                'table' => 'teachers',
10932                'alias' => 'Teacher',
10933                'conditions' => 'LessonOnairsLog.teacher_id = Teacher.id'
10934            ),
10935            array(
10936                'type' => 'LEFT',
10937                'table' => 'lesson_track_logs',
10938                'alias' => 'LessonTrackLogs',
10939                'conditions' => 'LessonTrackLogs.chat_hash = LessonOnairsLog.chat_hash'
10940            )
10941        );
10942        $lessonHistoryFields = array(
10943            'LessonOnairsLog.id',
10944            'LessonOnairsLog.start_time',
10945            'LessonOnairsLog.end_time',
10946            'LessonOnairsLog.created', //Lesson Data / time
10947            'LessonOnairsLog.chat_hash',
10948            'LessonOnairsLog.lesson_memo',
10949            'LessonOnairsLog.lesson_memo_disp_flg',
10950            'LessonOnairsLog.connect_id',
10951            'LessonOnairsLog.display_message',
10952            'LessonOnairsLog.teacher_id',
10953            'TextbookConnect.id',
10954            'usersClassEvaluations.rate', //Lesson rate
10955            'TextbookCategory.name',
10956            'TextbookCategory.type_id',
10957            'TextbookSubategory.name',
10958            'Textbook.name',
10959            'Teacher.id',
10960            'LessonTrackLogs.lesson_number'
10961        );
10962        $this->Teacher->openDBReplica();
10963        $subQuery = $this->Teacher->find(
10964            'list',
10965            array(
10966                'fields'     => array('Teacher.id'),
10967                'table'      => 'teachers',
10968                'alias'      => 'Teacher',
10969                'conditions' => array(
10970                    'Teacher.counseling_flg' => 1,
10971                    'Teacher.status' => 1
10972                ),
10973                'recursive' => -1
10974            )
10975        );
10976        $this->Teacher->closeDBReplica();
10977
10978        $lessonHistoryConditions = array(
10979            'LessonOnairsLog.teacher_id IN' => $subQuery,
10980            'LessonOnairsLog.user_id' => $userId,
10981            'LessonOnairsLog.delete_flg <> ' => $this->LessonOnairsLog::DELETED
10982        );
10983
10984        // - has localized directory
10985        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))){
10986            // - get the user's language id
10987            $langId = ClassRegistry::init('CountryCode')->getUserLanguageId($this->localizeDir);
10988            if ($langId) {
10989
10990                $lessonHistoryJoins[] = array(
10991                    'type' => 'LEFT',
10992                    'table' => 'global_textbook_categories',
10993                    'alias' => 'GlobalTextbookCategory',
10994                    'conditions' => array(
10995                        'GlobalTextbookCategory.language_id' => $langId,
10996                        'GlobalTextbookCategory.textbook_category_id = TextbookCategory.id'
10997                    )
10998                );
10999
11000                $lessonHistoryJoins[] = array(
11001                    'type' => 'LEFT',
11002                    'table' => 'global_textbook_subcategories',
11003                    'alias' => 'GlobalTextbookSubcategory',
11004                    'conditions' => array(
11005                        'GlobalTextbookSubcategory.language_id' => $langId,
11006                        'GlobalTextbookSubcategory.textbook_subcategory_id = TextbookSubategory.id'
11007                    )
11008                );
11009                $lessonHistoryJoins[] = array(
11010                    'type' => 'LEFT',
11011                    'table' => 'global_textbooks',
11012                    'alias' => 'GlobalTextbook',
11013                    'conditions' => array(
11014                        'GlobalTextbook.language_id' => $langId,
11015                        'GlobalTextbook.textbook_id = Textbook.id'
11016                    )
11017                );
11018                $this->LessonOnairsLog->virtualFields = array(
11019                    'gl_subcateg_name' => 'GlobalTextbookSubcategory.gl_name',
11020                    'gl_name' => 'GlobalTextbook.gl_name'
11021                );
11022                $lessonHistoryFields[] = 'gl_categ_name';
11023                $lessonHistoryFields[] = 'gl_subcateg_name';
11024                $lessonHistoryFields[] = 'gl_name';
11025            }
11026        }
11027
11028        // - get lesson history
11029        $this->LessonOnairsLog->openDBReplica();
11030        $latestLessonHistory = $this->LessonOnairsLog->find(
11031            'all',
11032            array(
11033                'joins' => $lessonHistoryJoins,
11034                'fields' => $lessonHistoryFields,
11035                'conditions' => $lessonHistoryConditions,
11036                'limit' => 10, //int
11037                'order' => 'LessonOnairsLog.start_time DESC'
11038            )
11039        );
11040        $this->LessonOnairsLog->closeDBReplica();
11041
11042        $this->set('lessonHistory', $latestLessonHistory);
11043        $this->set('textbookNamesCachedArr', $textbookNamesCachedArr);
11044        //NC-7984
11045    }
11046
11047
11048    //Retrieves the latest lesson history for a specific avatar teacher and user in Native Camp. It returns the lesson history data.
11049    public function avatarLatestLessonHistory($userId, $teacherId){
11050        $memcache = new myMemcached();
11051        $textbookNamesCachedArr = $memcache->get(Configure::read('textbook_names_cache_key'));
11052        //NC-7984
11053        $lessonHistoryJoins = array(
11054            "use index (user_id)",
11055            array(
11056                'type' => 'LEFT',
11057                'table' => 'users_class_evaluations',
11058                'alias' => 'usersClassEvaluations',
11059                'conditions' => array('usersClassEvaluations.chat_hash = LessonOnairsLog.chat_hash')
11060            ),
11061            array (
11062                'type' => 'LEFT',
11063                'table' => 'textbook_connects',
11064                'alias' => 'TextbookConnect',
11065                'conditions' => 'LessonOnairsLog.connect_id = TextbookConnect.id'
11066            ),
11067            array(
11068                'type' => 'LEFT',
11069                'table' => 'textbook_categories',
11070                'alias' => 'TextbookCategory',
11071                'conditions' => 'TextbookConnect.category_id = TextbookCategory.id'
11072            ),
11073            array(
11074                'type' => 'LEFT',
11075                'table' => 'textbook_subcategories',
11076                'alias' => 'TextbookSubategory',
11077                'conditions' => 'TextbookConnect.subcategory_id = TextbookSubategory.id'
11078            ),
11079            array(
11080                'type' => 'LEFT',
11081                'table' => 'textbooks',
11082                'alias' => 'Textbook',
11083                'conditions' => 'Textbook.id = TextbookConnect.textbook_id'
11084            ),
11085            array(
11086                'type' => 'LEFT',
11087                'table' => 'teachers',
11088                'alias' => 'Teacher',
11089                'conditions' => 'LessonOnairsLog.teacher_id = Teacher.id'
11090            ),
11091            array(
11092                'type' => 'LEFT',
11093                'table' => 'lesson_track_logs',
11094                'alias' => 'LessonTrackLogs',
11095                'conditions' => 'LessonTrackLogs.chat_hash = LessonOnairsLog.chat_hash'
11096            )
11097        );
11098        $lessonHistoryFields = array(
11099            'LessonOnairsLog.id',
11100            'LessonOnairsLog.start_time',
11101            'LessonOnairsLog.end_time',
11102            'LessonOnairsLog.created', //Lesson Data / time
11103            'LessonOnairsLog.chat_hash',
11104            'LessonOnairsLog.lesson_memo',
11105            'LessonOnairsLog.lesson_memo_disp_flg',
11106            'LessonOnairsLog.connect_id',
11107            'LessonOnairsLog.display_message',
11108            'TextbookConnect.id',
11109            'usersClassEvaluations.rate', //Lesson rate
11110            'TextbookCategory.name',
11111            'TextbookCategory.type_id',
11112            'TextbookSubategory.name',
11113            'Textbook.name',
11114            'Teacher.id',
11115            'LessonTrackLogs.lesson_number'
11116        );
11117        $this->Teacher->openDBReplica();
11118        $subQuery = $this->Teacher->find(
11119            'list',
11120            array(
11121                'fields'     => array('Teacher.id'),
11122                'table'      => 'teachers',
11123                'alias'      => 'Teacher',
11124                'conditions' => array(
11125                    "(Teacher.avatar_flg = 1 AND Teacher.counseling_flg = 0 AND Teacher.status = 1 AND Teacher.avatar_id = {$teacherId}) || (Teacher.avatar_parent_flg = 1 AND Teacher.id = {$teacherId})"
11126                ),
11127                'recursive' => -1
11128            )
11129        );
11130        $this->Teacher->closeDBReplica();
11131
11132        $lessonHistoryConditions = array(
11133            'LessonOnairsLog.user_id' => $userId,
11134            'LessonOnairsLog.delete_flg <> ' => $this->LessonOnairsLog::DELETED
11135        );
11136
11137        if(is_array($subQuery) && !empty($subQuery)){
11138            $lessonHistoryConditions['LessonOnairsLog.teacher_id IN'] = $subQuery;
11139        }
11140
11141        // - has localized directory
11142        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))){
11143            // - get the user's language id
11144            $langId = ClassRegistry::init('CountryCode')->getUserLanguageId($this->localizeDir);
11145            if ($langId) {
11146
11147                $lessonHistoryJoins[] = array(
11148                    'type' => 'LEFT',
11149                    'table' => 'global_textbook_categories',
11150                    'alias' => 'GlobalTextbookCategory',
11151                    'conditions' => array(
11152                        'GlobalTextbookCategory.language_id' => $langId,
11153                        'GlobalTextbookCategory.textbook_category_id = TextbookCategory.id'
11154                    )
11155                );
11156
11157                $lessonHistoryJoins[] = array(
11158                    'type' => 'LEFT',
11159                    'table' => 'global_textbook_subcategories',
11160                    'alias' => 'GlobalTextbookSubcategory',
11161                    'conditions' => array(
11162                        'GlobalTextbookSubcategory.language_id' => $langId,
11163                        'GlobalTextbookSubcategory.textbook_subcategory_id = TextbookSubategory.id'
11164                    )
11165                );
11166                $lessonHistoryJoins[] = array(
11167                    'type' => 'LEFT',
11168                    'table' => 'global_textbooks',
11169                    'alias' => 'GlobalTextbook',
11170                    'conditions' => array(
11171                        'GlobalTextbook.language_id' => $langId,
11172                        'GlobalTextbook.textbook_id = Textbook.id'
11173                    )
11174                );
11175
11176                $lessonHistoryFields[] = 'GlobalTextbookCategory.gl_name';
11177                $lessonHistoryFields[] = 'GlobalTextbookSubcategory.gl_name';
11178                $lessonHistoryFields[] = 'GlobalTextbook.gl_name';
11179            }
11180        }
11181
11182        // - get lesson history
11183        $this->LessonOnairsLog->openDBReplica();
11184        $latestLessonHistory = $this->LessonOnairsLog->find(
11185            'all',
11186            array(
11187                'joins' => $lessonHistoryJoins,
11188                'fields' => $lessonHistoryFields,
11189                'conditions' => $lessonHistoryConditions,
11190                'limit' => 10, //int
11191                'order' => 'LessonOnairsLog.start_time DESC'
11192            )
11193        );
11194        $this->LessonOnairsLog->closeDBReplica();
11195
11196        $this->set('lessonHistory', $latestLessonHistory);
11197        $this->set('textbookNamesCachedArr', $textbookNamesCachedArr);
11198        //NC-7984
11199    }
11200
11201    private function userAvailPopularTeacher($params=array()){
11202        $result = false;
11203        if ( isset($params['user_id']) && isset($params['avatar_id']) ) {
11204            $userId = $params['user_id'];
11205            $avatarId = $params['avatar_id'];
11206
11207            $getTeacherAvatars = $this->Teacher->getAvatarTeacherId($params);
11208            if ($getTeacherAvatars) {
11209                $disconCancel = Configure::read('accounting.disconnection_cancellation_lesson_finish');
11210                // - check if has db replica
11211                $this->LessonOnairsLog->openDBReplica();
11212                $countLessons = $this->LessonOnairsLog->find('count', array(
11213                        'conditions' => array(
11214                        'LessonOnairsLog.user_id' => $userId,
11215                        'LessonOnairsLog.teacher_id' => array_values($getTeacherAvatars),
11216                        'LessonOnairsLog.start_time IS NOT NULL',
11217                        'LessonOnairsLog.end_time IS NOT NULL',
11218                        'LessonOnairsLog.connect_id IS NOT NULL',
11219                        'LessonOnairsLog.lesson_finish' => 1
11220                    ),
11221                    'recursive' => -1
11222                ));
11223                $this->LessonOnairsLog->closeDBReplica();
11224
11225                if ($countLessons < 1) {
11226                    $result = true;
11227                }
11228
11229            }
11230
11231        }
11232        return $result;
11233    }
11234
11235
11236    //NC-8728 check if user is valid for Study Sapuri Business English Daily textbooks
11237    private function userValidForSSBEDT(){
11238        $userValidForSSBEDT = false;
11239        if (
11240              (isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')) &&
11241              ($this->Auth->loggedIn() && $this->Auth->user('currency_code') == Configure::read('default.user_currency'))
11242        ){
11243            $userValidForSSBEDT = true;
11244        }
11245
11246        return $userValidForSSBEDT;
11247    }
11248
11249    /**
11250     * @api {post} /user/waiting/loadLiveLessonTeacher loadLiveLessonTeacher()
11251     * @apiName loadLiveLessonTeacher
11252     * @apiGroup Waiting
11253     * @apiDescription Retrieves the list of teachers available for live lessons in Native Camp. It checks if the request is an AJAX request and returns the list of live lesson teachers.
11254     *
11255     * @apiBody {Number} [current_page=1] The current page number.
11256     * @apiBody {Number} [limit] The limit of teachers to retrieve.
11257     * @apiBody {String} [local_timezone] The local timezone of the user.
11258     * @apiBody {Boolean} [isGuestViwer] Indicates whether the user is a guest viewer.
11259     * @apiBody {Boolean} [isMobile] Indicates whether the request is from a mobile device.
11260     * @apiBody {String} [template] The template to use for rendering the teacher list.
11261     * @apiBody {String} [token] The API token of the user.
11262     * 
11263     * @apiSuccess {Object[]} liveTeacherList The list of teachers available for live lessons.
11264     * @apiSuccess {String} liveTeacherList.name The teacher's name.
11265     * @apiSuccess {String} liveTeacherList.id The teacher's unique identifier.
11266     * @apiSuccess {String} liveTeacherList.profilePicture URL to the teacher's profile picture.
11267     * @apiSuccess {Boolean} ajaxDisplay Indicates if the request was made via AJAX.
11268     * @apiSuccess {Number} userJpTimeDiffSecond The time difference in seconds between the user's local time and Japan time.
11269     * @apiSuccess {Number} studentLessonPriorityTimeDelayInSeconds The delay in seconds for student lesson priority.
11270     * @apiSuccess {Object} teacherListLiveParameters The parameters for the live teacher list (if applicable).
11271     * @apiSuccess {String} teacherListLiveParameters.user_id The ID of the user.
11272     * @apiSuccess {String} teacherListLiveParameters.user_language The language of the user.
11273     * @apiSuccess {Boolean} teacherListLiveParameters.pc_view Indicates if the view is for PC.
11274     * @apiSuccess {Number} teacherListLiveParameters.page The current page number.
11275     * @apiSuccess {String} teacherListLiveParameters.template The template used for rendering the teacher list.
11276     * @apiSuccess {Boolean} teacherListLiveParameters.mobapp_view Indicates if the view is for mobile app.
11277     * @apiSuccess {Number} teacherListLiveParameters.limit The limit of teachers to retrieve.
11278     * @apiSuccess {Boolean} teacherListLiveParameters.isGuestViwer Indicates if the user is a guest viewer.
11279     * @apiSuccess {Boolean} teacherListLiveParameters.isMobile Indicates if the request is from a mobile device.
11280     *
11281     * @apiSuccessExample {json} Success-Response:
11282     *     {
11283     *         "liveTeacherList": [
11284     *             {
11285     *                 "name": "Teacher Name",
11286     *                 "id": "123456",
11287     *                 "profilePicture": "https://www.nativecamp.net/img/teacher/123456.jpg"
11288     *             },
11289     *             ...
11290     *         ],
11291     *         "ajaxDisplay": true,
11292     *         "userJpTimeDiffSecond": 32400,
11293     *         "studentLessonPriorityTimeDelayInSeconds": 60,
11294     *         "teacherListLiveParameters": {
11295     *             "user_id": "789",
11296     *             "user_language": "en",
11297     *             "pc_view": true,
11298     *             "page": 1,
11299     *             "template": "pc_usage",
11300     *             "mobapp_view": false,
11301     *             "limit": 10,
11302     *             "isGuestViwer": false,
11303     *             "isMobile": false
11304     *         }
11305     *     }
11306     *
11307     * @apiError {String} error Message indicating the error.
11308     *
11309     * @apiErrorExample {json} Error-Response:
11310     *     {
11311     *         "error": "Invalid request."
11312     *     }
11313     * 
11314     * @apiSampleRequest off
11315     */
11316    public function loadLiveLessonTeacher(){
11317        $data = $this->request->data;
11318        $liveTeacherList = array();
11319        $params = array();
11320        $currentPage = !empty($data['current_page']) ? $data['current_page'] : 1 ;
11321        $limit = isset($data['limit']) ? $data['limit'] : null;
11322        $userJpTimeDiffSecond = !empty($this->timeDiffSecond) ? $this->timeDiffSecond : 0;
11323        $isGuestViwer = !empty($data['isGuestViwer']) ? 1 : 0;
11324
11325        //- if token set
11326        if (!empty($this->request->query['token'])) {
11327            $this->User->openDBReplica();
11328            $this->sharedUserData = $this->User->find('first', [
11329                'conditions' => ['api_token' => $this->request->query['token']],
11330                'recursive' => -1
11331            ]);
11332            $this->User->closeDBReplica();
11333
11334        }
11335
11336        //-- get JP time difference for logout users
11337        if (
11338            (empty($this->sharedUserData['User']) || $isGuestViwer)
11339            && !empty($data['local_timezone'])
11340            && $data['local_timezone'] != 'Asia/Tokyo'
11341        ) {
11342            $localTimezoneName = explode('/', $data['local_timezone']);
11343            if ( !empty($localTimezoneName[1]) ) {
11344                $this->Timezone->openDBReplica();
11345                $jpTimeDiff = $this->Timezone->find('first', array(
11346                    'fields' => 'jp_time_diff',
11347                    'conditions' => array(
11348                        'Timezone.city_eng LIKE ? ' => array($localTimezoneName[1])
11349                    ),
11350                    'recursive' => -1
11351                ));
11352                $this->Timezone->closeDBReplica();
11353                $userJpTimeDiffSecond = !empty($jpTimeDiff['Timezone']['jp_time_diff']) ? ((int)$jpTimeDiff['Timezone']['jp_time_diff'] * 60) : $userJpTimeDiffSecond;
11354            }
11355        }
11356
11357        //-- check if current user can use live lesson
11358        if ( 
11359            $isGuestViwer
11360            || empty($this->sharedUserData['User']) 
11361            || UserTable::canJoinLiveViewing($this->sharedUserData['User'])
11362        ){
11363            //-- set list of params for teacher live lessons
11364            $params = array(
11365                'user_id' => !empty($this->sharedUserData['User']['id']) ? $this->sharedUserData['User']['id'] : null,
11366                'payment_plan_id' => !empty($this->sharedUserData['User']['payment_plan_id']) ? $this->sharedUserData['User']['payment_plan_id'] : null,
11367                'currency_code' => !empty($this->sharedUserData['User']['currency_code']) ? $this->sharedUserData['User']['currency_code'] : null,
11368                'user_language' => isset($this->localizeDir) ? $this->localizeDir : $this->sharedUserData['User']['native_language2'],
11369                'pc_view' => true,
11370                'page' => $currentPage,
11371                'template' => isset($data['template']) ? $data['template'] : '',
11372                'mobapp_view' => isset($data['template']) ? true : false,
11373                'limit' => $limit,
11374                'isGuestViwer' => $isGuestViwer,
11375                'isMobile' => !empty($data['isMobile']) ? 1 : 0, // TODO: Add new key-value pair if it is an SP view or mobileApp
11376            );
11377            // Get list of teachers for live lessons
11378            $liveTeacherList = $this->CommonTeacherStatus->liveTeacherList($params);
11379        }
11380        //-- return blank respond
11381        if ( empty($liveTeacherList) ) {
11382            $this->autoRender = false;
11383            $this->layout = false;
11384            return false;
11385        }
11386        // - pass view parameters
11387        $this->set('ajaxDisplay', true);
11388        $this->set('userJpTimeDiffSecond', $userJpTimeDiffSecond);
11389        $this->set('liveTeacherList', $liveTeacherList);
11390        $this->set('studentLessonPriorityTimeDelayInSeconds', (int)$this->studentLessonPriorityTimeDelayInSeconds);
11391        //-- if guest viwer with SP screen
11392        if ( $isGuestViwer && !empty($data['isMobile']) ) {
11393            $this->set('teacherListLiveParameters', $params); //TODO:: Pass the params to live_teacher_banner only in SP_side
11394            return $this->render('/Elements/mobile/live_teacher_banner_list');
11395        }
11396
11397        // - if usage template
11398        if (isset($data['template']) && in_array($data['template'], ["pc_usage", "mobapp_usage"])) {
11399            return $this->render('/Elements/live_teacher_pc_usage_list');
11400
11401        // - else use default
11402        } else {
11403            return $this->render('/Elements/live_teacher_banner_list');
11404        }
11405    }
11406
11407    /**
11408     * @api {get} /user/waiting/sms_questionnaire sms_questionnaire()
11409     * @apiName sms_questionnaire
11410     * @apiGroup Waiting
11411     * @apiDescription Redirects the user to the SMS questionnaire page for a specific teacher in Native Camp. It sets the origin and success URLs in the session and redirects to the SMS questionnaire page.
11412     *
11413     * @apiBody {String} teacherId The ID of the teacher.
11414     * 
11415     * @apiSuccess {String} redirect The URL to redirect to.
11416     *
11417     * @apiSuccessExample {view} Redirect-Response:
11418     *  - Redirects to the /account/sms_questionnaire page.
11419     *
11420     * @apiError {String} error Message indicating the error.
11421     *
11422     * @apiErrorExample {json} Error-Response:
11423     *     {
11424     *         "error": "Invalid request."
11425     *     }
11426     * 
11427     * @apiSampleRequest off
11428     */
11429    public function sms_questionnaire($teacherId = null) {
11430        if (is_null($teacherId)) {
11431            return $this->redirect(myTools::getUrl() . '/user/waiting', 301);
11432        }
11433        $data = array(
11434            'origin_url' => '/waiting/detail/'.$teacherId,
11435            'success_url' => '/waiting/detail/'.$teacherId
11436        );        
11437        $this->Session->write($data);
11438        return $this->redirect('/account/sms_questionnaire');
11439    }
11440    
11441    /**
11442     * @api {get} /user/waiting/avatar_sms_questionnaire avatar_sms_questionnaire()
11443     * @apiName avatar_sms_questionnaire
11444     * @apiGroup Waiting
11445     * @apiDescription Redirects the user to the SMS questionnaire page for a specific avatar teacher in Native Camp. It sets the origin and success URLs in the session and redirects to the SMS questionnaire page.
11446     *
11447     * @apiBody {String} teacherId The ID of the avatar teacher.
11448     * 
11449     * @apiSuccess {String} redirect The URL to redirect to.
11450     *
11451     * @apiSuccessExample {view} Redirect-Response:
11452     *  - Redirects to the /account/sms_questionnaire page.
11453     *
11454     * @apiError {String} error Message indicating the error.
11455     *
11456     * @apiErrorExample {json} Error-Response:
11457     *     {
11458     *         "error": "Invalid request."
11459     *     }
11460     * 
11461     * @apiSampleRequest off
11462     */
11463    public function avatar_sms_questionnaire($teacherId = null) {
11464        if (is_null($teacherId)) {
11465            return $this->redirect(myTools::getUrl() . '/user/waiting', 301);
11466        }
11467        $data = array(
11468            'origin_url' => '/avatar_detail/'.$teacherId,
11469            'success_url' => '/avatar_detail/'.$teacherId
11470        );        
11471        $this->Session->write($data);
11472        return $this->redirect('/account/sms_questionnaire');
11473    }
11474
11475    /**
11476     * @api {post} /user/waiting/checkCounselorTeacherButtonStatus checkCounselorTeacherButtonStatus()
11477     * @apiName checkCounselorTeacherButtonStatus
11478     * @apiGroup Waiting
11479     * @apiDescription Checks the status of the counselor teacher button for the authenticated user in Native Camp. It returns the availability of the counselor teacher, whether the daily limit is exceeded, and other related data.
11480     *
11481     * @apiBody {Boolean} [dev_test] Indicates whether the request is for development testing.
11482     * @apiBody {Boolean} [customer_support_flg] Indicates whether customer support is enabled.
11483     * 
11484     * @apiSuccess {String} available_teacher The ID of the available teacher.
11485     * @apiSuccess {Boolean} exceed_daily_limit Indicates whether the daily limit is exceeded.
11486     * @apiSuccess {Number} res The result status (0: Not available, 1: Available, 3: Logout).
11487     * @apiSuccess {String} chat_hash The chat hash.
11488     * @apiSuccess {Number} Membership type for checking if the user is not free trial
11489     *
11490     * @apiSuccessExample {json} Success-Response:
11491     *     {
11492     *         "available_teacher": "123",
11493     *         "exceed_daily_limit": 0,
11494     *         "res": 1,
11495     *         "chat_hash": "example_chat_hash",
11496     *            "membership_type": "example_membership_type"
11497     *     }
11498     *
11499     * @apiError {String} error Message indicating the error.
11500     *
11501     * @apiErrorExample {json} Error-Response:
11502     *     {
11503     *         "error": "Invalid request."
11504     *     }
11505     * 
11506     * @apiSampleRequest off
11507     */
11508    public function checkCounselorTeacherButtonStatus() {
11509        $this->autoRender = false;
11510        $this->layout = false;
11511        
11512        $result = 0; // Not available
11513        $devTest = isset($this->request->query['dev_test']) && $this->request->query['dev_test'] ? 1 : 0;
11514
11515        if (isset($this->request->data['customer_support_flg']) && ( $this->request->data['customer_support_flg'] == 'false' || $this->request->data['customer_support_flg'] == false )) {
11516            $customer_support_flg = 0;
11517        }else{
11518            $customer_support_flg = 1;
11519        }
11520        $userId = $this->Auth->user('id');
11521        $teacherId = 0;
11522        $exceedDailyLimit = false;
11523        $chat_hash = null;
11524        $userData = $this->sharedUserData['User'];
11525        if ( $this->request->is('ajax') || $devTest ) {
11526            if ( $userId ) {
11527                $counselorParams = array(
11528                    'user_id' => $userId,
11529                    'user_data' => $userData,
11530                    'customer_support_flg' => $customer_support_flg
11531                );
11532                $data = $this->LessonOnair->checkCounselorTeacherButtonStatus($counselorParams);
11533                $dataObj = json_decode($data,true);
11534                $teacherId = $dataObj['available_teacher'] ?? '';
11535                $exceedDailyLimit = $dataObj['exceed_daily_limit'] ?? '';
11536                $result = $dataObj['res'] ?? '';
11537                $chat_hash = $dataObj['chat_hash'] ?? '';
11538            } else {
11539                $result = 3; // logout
11540            }
11541        }
11542
11543        if($userId){
11544            $csList = ($customer_support_flg == 1) ? $this->Teacher->getCustomerSupportTeachers() : $this->Teacher->getCounselorTeachers();
11545            $csExceedLimitCheck = $this->LessonOnairsLog->checkExceedCSLimit($userId, ($customer_support_flg == 1) ?  $csList['customerSupportId'] : $csList['counselorId']);
11546            if($csExceedLimitCheck){
11547                $exceedDailyLimit = true;
11548            }
11549        }
11550
11551        return json_encode(
11552            array(
11553                'available_teacher' => $teacherId,
11554                'exceed_daily_limit' => ( $exceedDailyLimit ) ? 1 : 0,
11555                'res' => $result,
11556                'chat_hash' => $chat_hash,
11557                'membership_type' => $this->userMembershipType
11558            )
11559        );
11560    }
11561
11562    /**
11563     * @api {get} /user/emergency emergencyLesson()
11564     * @apiName emergencyLesson
11565     * @apiGroup Waiting
11566     * @apiDescription Retrieves the emergency lesson data for the authenticated user in Native Camp. It checks if the user is a Study Sapuri TOS user and returns the preset textbook data.
11567     * 
11568     * @apiSuccess {Object} preset The preset textbook data.
11569     * @apiSuccess {String} preset.textbook_connect_id The ID of the textbook connect.
11570     * @apiSuccess {String} preset.textbook_type The type of the textbook.
11571     * @apiSuccess {Object} searchData The saved search condition data.
11572     * @apiSuccess {String} textbookConnectId The ID of the textbook connect.
11573     * @apiSuccess {String} textbookCategoryTypeId The type ID of the textbook category.
11574     *
11575     * @apiSuccessExample {json} Success-Response
11576     *     {
11577     *         "preset": {
11578     *             "textbook_connect_id": "123",
11579     *             "textbook_type": "1"
11580     *         },
11581     *         "searchData": {...},
11582     *         "textbookConnectId": "123",
11583     *         "textbookCategoryTypeId": "1"
11584     *     }
11585     *
11586     * @apiError {String} error Message indicating the error.
11587     *
11588     * @apiErrorExample {json} Error-Response:
11589     *     {
11590     *         "error": "Not Found"
11591     *     }
11592     * 
11593     * @apiSampleRequest off
11594     */
11595    public function emergencyLesson() {
11596        if (!$this->isStudySapuriTosUser) {
11597            throw new NotFoundException();
11598        }
11599
11600        $presetParams = array("user_id" => $this->Auth->user('id'));
11601        $preset_data = $this->UsersTextbookInfo->getPreset($presetParams);
11602        if(isset($preset_data['preset_connect_id']) && !empty($preset_data['preset_connect_id'])) {
11603                # for preset
11604                $presetParams['connect_id'] = $preset_data['preset_connect_id'];
11605                $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
11606        } else if(isset($preset_data['last_viewed_connect_id']) && !empty($preset_data['last_viewed_connect_id'])) {
11607                # use last viewed textbook if no preset data.
11608                $presetParams['connect_id'] = $preset_data['last_viewed_connect_id'];
11609                $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
11610        }
11611        
11612        # fetch preset 
11613        $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
11614        if(!$preset) {
11615                unset($presetParams['connect_id']);
11616                unset($presetParams['last_opened_date']);
11617                $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
11618        }
11619
11620        // NC-7228 set series id from saved search condition
11621        $searchData = $this->Cookie->read('searchData');
11622        $this->set('preset', $preset);
11623        $this->set('searchData', $searchData);
11624        $this->set('textbookConnectId', $preset['textbook_connect_id']);
11625        $this->set('textbookCategoryTypeId', $preset['textbook_type']);
11626        return $this->render('/Waiting/emergency_lesson');
11627    }
11628    
11629    /**
11630     * @api {post} /user/waiting/teacherBadgeList teacherBadgeList()
11631     * @apiName teacherBadgeList
11632     * @apiGroup Waiting
11633     * @apiDescription Retrieves the badge list for a specific teacher in Native Camp. It checks if the request is an AJAX request and returns the badge list data.
11634     *
11635     * @apiBody {String} teacherId The ID of the teacher.
11636     * @apiBody {Boolean} [sp] Indicates whether the request is from SP.
11637     * 
11638     * @apiSuccess {Object[]} series The series data.
11639     * @apiSuccess {String} series.TextbookCategory.name The name of the textbook category.
11640     * @apiSuccess {String} series.TextbookCategory.id The ID of the textbook category.
11641     * @apiSuccess {String} series.TextbookCategory.type_id The type ID of the textbook category.
11642     * @apiSuccess {String} series.TeacherBadge.textbook_category_id The textbook category ID of the teacher badge.
11643     * @apiSuccess {Boolean} series.TeacherBadge.badge_flg The badge flag of the teacher badge.
11644     * @apiSuccess {String} series.TextbookCategory.image_big_url The image URL of the textbook category.
11645     * @apiSuccess {String} [series.gl_name] The global name of the textbook category (if available).
11646     * @apiSuccess {Object} teacherTbRatings The teacher textbook ratings data.
11647     * @apiSuccess {Number} teacherTbRatings.teacher_textbook_rating The rating of the teacher for the textbook category.
11648     * @apiSuccess {Object[]} titleThresholdTextbookList The title threshold textbook list data.
11649     * @apiSuccess {String} titleThresholdTextbookList.title The title of the threshold.
11650     * @apiSuccess {Number} titleThresholdTextbookList.threshold The threshold value.
11651     *
11652     * @apiSuccessExample {json} Success-Response:
11653     *     {
11654     *         "series": [
11655     *             {
11656     *                 "TextbookCategory": {
11657     *                     "name": "Category Name",
11658     *                     "id": "1",
11659     *                     "type_id": "2",
11660     *                     "image_big_url": "http://example.com/image.jpg"
11661     *                 },
11662     *                 "TeacherBadge": {
11663     *                     "textbook_category_id": "1",
11664     *                     "badge_flg": true
11665     *                 },
11666     *                 "gl_name": "Global Category Name"
11667     *             }
11668     *         ],
11669     *         "teacherTbRatings": {
11670     *             "1": {
11671     *                 "teacher_textbook_rating": 4.5
11672     *             }
11673     *         },
11674     *         "titleThresholdTextbookList": [
11675     *             {
11676     *                 "title": "Expert",
11677     *                 "threshold": 100
11678     *             },
11679     *             {
11680     *                 "title": "Master",
11681     *                 "threshold": 200
11682     *             }
11683     *         ]
11684     *     }
11685     *
11686     * @apiError {String} error Message indicating the error.
11687     *
11688     * @apiErrorExample {json} Error-Response:
11689     *     {
11690     *         "error": "Invalid request."
11691     *     }
11692     * 
11693     * @apiSampleRequest off
11694     */
11695    public function teacherBadgeList() {
11696        $this->layout = "";
11697        if (!$this->request->is('ajax')) { return ; }
11698        
11699        $teacherId = $this->request->data['teacherId'];
11700        if (empty($teacherId)) { return ; }
11701
11702        $fieldArr = array(
11703            'TextbookCategory.name',
11704            'TextbookCategory.id',
11705            'TextbookCategory.type_id',
11706            'TeacherBadge.textbook_category_id',
11707            'TeacherBadge.badge_flg',
11708            'TextbookCategory.type_id',
11709            'TextbookCategory.image_big_url'
11710        );
11711        $joinArr = array(
11712            array(
11713                'table' => 'teacher_badges',
11714                'alias' => 'TeacherBadge',
11715                'type' => 'INNER',
11716                'conditions' => array(
11717                    'TeacherBadge.textbook_category_id = TextbookCategory.id',
11718                    'TeacherBadge.teacher_id' => $teacherId)
11719            )
11720        );
11721
11722        // if the user's language is zh-tw, display chinese textbook badge name
11723        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))){
11724            $langId = ClassRegistry::init('CountryCode')->getUserLanguageId($this->localizeDir);
11725            if($langId){
11726                $joinArr[] = array(
11727                    'type' => 'LEFT',
11728                    'table' => 'global_textbook_categories',
11729                    'alias' => 'GlobalTextbookCategory',
11730                    'conditions' => array(
11731                        'GlobalTextbookCategory.language_id' => $langId,
11732                        'GlobalTextbookCategory.textbook_category_id = TextbookCategory.id'
11733                    )
11734                );
11735                $this->TextbookCategory->virtualFields = array(
11736                    'gl_name' => 'GlobalTextbookCategory.gl_name'
11737                );
11738                $fieldArr[] = 'gl_name';
11739            }
11740        }
11741
11742        $conArr = array(
11743            'TextbookCategory.status' => 1,
11744            'TextbookCategory.type_id' => 2
11745        );
11746
11747        # get studydapuri textbooks
11748        $studysapuriType = Configure::read('studysapuri_textbook_category_types');
11749        if ( $this->studySapuriId && isset($this->sharedUserData['User']['payment_plan_id']) ) {
11750            $plan = myTools::studySapuriContractPlan($this->sharedUserData['User']['payment_plan_id']);
11751            $conArr['TextbookCategory.textbook_category_type'] = $studysapuriType[$plan];
11752        } elseif ($this->isStudySapuriTosUser) {
11753            $conArr['TextbookCategory.textbook_category_type'] = Configure::read('stasapu_tos_textbook_category_type');
11754        } else {
11755            $exCat = Configure::read('all_sapuri_textbook_category_types');
11756            $conArr['NOT'] = array('TextbookCategory.textbook_category_type' => $exCat);
11757        }
11758
11759        // NJ-5836
11760        $displayRestrictionParams = array(
11761            'lang' => $this->localizeDir
11762        );
11763
11764        // get display restriction setting
11765        $displayRestriction = $this->TextbookCategory->getDisplayRestrictionSettings($displayRestrictionParams);
11766
11767        // NJ-5836 add condition for display restriction
11768        if(isset($displayRestriction['field']) && $displayRestriction['field']){
11769            // set condition for display restriction
11770            $conArr['TextbookCategory.'.$displayRestriction['field']] = 1;
11771        }
11772
11773        //get series and badge
11774        $series = $this->TextbookCategory->find('all', array(
11775            'fields' => $fieldArr,
11776            'conditions' => $conArr,
11777            'joins' => $joinArr,
11778            'order' => array(
11779                'TextbookCategory.sort' => 'ASC'
11780            )
11781        ));
11782
11783        $this->set('series', $series);            
11784        
11785        $teacherTbRatings = array();
11786        if($series && is_array($series)) {
11787            foreach($series as $key => $books){            
11788                $categoryId = $books['TextbookCategory']['id'];
11789                $params = array(
11790                    'teacher_id' =>  (int) $teacherId,
11791                    'textbook_category_id' => (int) $categoryId,
11792                    'nc_terminal_type' => Configure::read('nc_terminal_type.pc')
11793                );    
11794                $decodeResp = json_decode($this->TeacherTextbookStat->teacherTextbookRating($params));
11795                $teacherTbRatings[$categoryId] = $decodeResp->teacher_textbook_rating;
11796            }
11797        }
11798        $this->set('teacherTbRatings', $teacherTbRatings);
11799
11800        // NJ-17264
11801        $titleThresholdTextbookList = $this->TitleThresholdTeacher->getTitleTresholdPerTextbookCategory(['teacherId' => $teacherId, 'type' => 0]);    
11802
11803        $this->set('titleThresholdTextbookList', $titleThresholdTextbookList);
11804
11805        // new UI
11806        $this->render('teacher_badge_list');
11807        if( isset($this->request->data['sp']) && $this->request->data['sp'] ) {
11808            $this->render('sp_teacher_badge_list');
11809        }
11810    }
11811
11812    /**
11813     * @api {post} /user/waiting/avatarBadgeList avatarBadgeList()
11814     * @apiName avatarBadgeList
11815     * @apiGroup Waiting
11816     * @apiDescription Retrieves the badge list for a specific avatar teacher in Native Camp. It checks if the request is an AJAX request and returns the badge list data.
11817     *
11818     * @apiBody {String} teacher_avatar_id The ID of the avatar teacher.
11819     * @apiBody {Boolean} [sp] Indicates whether the request is from SP.
11820     * 
11821     * @apiSuccess {Object[]} series The series data.
11822     * @apiSuccess {String} series.TextbookCategory.name The name of the textbook category.
11823     * @apiSuccess {String} series.TextbookCategory.id The ID of the textbook category.
11824     * @apiSuccess {String} series.TextbookCategory.type_id The type ID of the textbook category.
11825     * @apiSuccess {String} series.TeacherBadge.textbook_category_id The textbook category ID of the teacher badge.
11826     * @apiSuccess {Boolean} series.TeacherBadge.badge_flg The badge flag of the teacher badge.
11827     * @apiSuccess {String} series.TextbookCategory.image_big_url The image URL of the textbook category.
11828     * @apiSuccess {String} [series.gl_name] The global name of the textbook category (if available).
11829     * @apiSuccess {Object} avatarTbRatings The avatar textbook ratings data.
11830     * @apiSuccess {Number} avatarTbRatings.teacher_textbook_rating The rating of the teacher for the textbook category.
11831     *
11832     * @apiSuccessExample {json} Success-Response:
11833     *     {
11834     *         "series": [
11835     *             {
11836     *                 "TextbookCategory": {
11837     *                     "name": "Category Name",
11838     *                     "id": "1",
11839     *                     "type_id": "2",
11840     *                     "image_big_url": "http://example.com/image.jpg"
11841     *                 },
11842     *                 "TeacherBadge": {
11843     *                     "textbook_category_id": "1",
11844     *                     "badge_flg": true
11845     *                 },
11846     *                 "gl_name": "Global Category Name"
11847     *             }
11848     *         ],
11849     *         "avatarTbRatings": {
11850     *             "1": {
11851     *                 "teacher_textbook_rating": 4.5
11852     *             }
11853     *         }
11854     *     }
11855     *
11856     * @apiError {String} error Message indicating the error.
11857     *
11858     * @apiErrorExample {json} Error-Response:
11859     *     {
11860     *         "error": "Invalid request."
11861     *     }
11862     * 
11863     * @apiSampleRequest off
11864     */
11865    public function avatarBadgeList() {
11866        $this->layout = "";
11867
11868        if (!$this->request->is('ajax')) { return; }
11869        
11870        $avatarId = Sanitize::escape($this->request->data['teacher_avatar_id']);
11871
11872        if (empty($avatarId)) { return; }
11873
11874        $fieldArr = array(
11875            'TextbookCategory.name',
11876            'TextbookCategory.id',
11877            'TextbookCategory.type_id',
11878            'TeacherBadge.textbook_category_id',
11879            'TeacherBadge.badge_flg',
11880            'TextbookCategory.type_id',
11881            'TextbookCategory.image_big_url'
11882        );
11883        $joinArr = array(
11884            array(
11885                'table' => 'teacher_badges',
11886                'alias' => 'TeacherBadge',
11887                'type' => 'INNER',
11888                'conditions' => array('TeacherBadge.textbook_category_id = TextbookCategory.id', 'TeacherBadge.teacher_id' => $avatarId)
11889            )
11890        );
11891
11892        // if the user's language is zh-tw, display chinese textbook badge name
11893        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))){
11894            $langId = ClassRegistry::init('CountryCode')->getUserLanguageId($this->localizeDir);
11895            if($langId){
11896                $joinArr[] = array(
11897                    'type' => 'LEFT',
11898                    'table' => 'global_textbook_categories',
11899                    'alias' => 'GlobalTextbookCategory',
11900                    'conditions' => array(
11901                        'GlobalTextbookCategory.language_id' => $langId,
11902                        'GlobalTextbookCategory.textbook_category_id = TextbookCategory.id'
11903                    )
11904                );
11905                $this->TextbookCategory->virtualFields = array(
11906                    'gl_name' => 'GlobalTextbookCategory.gl_name'
11907                );
11908                $fieldArr[] = 'gl_name';
11909            }
11910        }
11911
11912        $conArr = array(
11913            'TextbookCategory.status' => 1,
11914            'TextbookCategory.type_id' => 2
11915        );
11916
11917        # get studydapuri textbooks
11918        $studysapuriType = Configure::read('studysapuri_textbook_category_types');
11919        if ( $this->studySapuriId && isset($this->sharedUserData['User']['payment_plan_id']) ) {
11920            $plan = myTools::studySapuriContractPlan($this->sharedUserData['User']['payment_plan_id']);
11921            $conArr['TextbookCategory.textbook_category_type'] = $studysapuriType[$plan];
11922        } elseif ($this->isStudySapuriTosUser) {
11923            $conArr['TextbookCategory.textbook_category_type'] = Configure::read('stasapu_tos_textbook_category_type');
11924        } else {
11925            $exCat = Configure::read('all_sapuri_textbook_category_types');
11926            $conArr['NOT'] = array('TextbookCategory.textbook_category_type' => $exCat);
11927        }
11928
11929        // NJ-5836
11930        $displayRestrictionParams = array(
11931            'lang' => $this->localizeDir
11932        );
11933
11934        // get display restriction setting
11935        $displayRestriction = $this->TextbookCategory->getDisplayRestrictionSettings($displayRestrictionParams);
11936
11937        // NJ-5836 add condition for display restriction
11938        if(isset($displayRestriction['field']) && $displayRestriction['field']){
11939            // set condition for display restriction
11940            $conArr['TextbookCategory.'.$displayRestriction['field']] = 1;
11941        }
11942
11943        //get series and badge
11944        $series = $this->TextbookCategory->find('all', array(
11945            'fields' => $fieldArr,
11946            'conditions' => $conArr,
11947            'joins' => $joinArr,
11948            'order' => array(
11949                'TextbookCategory.sort' => 'ASC'
11950            )
11951        ));
11952
11953        $this->set('series', $series);
11954
11955        $avatarTbRatings = array();
11956        if($series && is_array($series)) {
11957            foreach($series as $key => $books){            
11958                $categoryId = $books['TextbookCategory']['id'];
11959                $params = array(
11960                    'avatar_id' => $avatarId,
11961                    'textbook_category_id' => (int) $categoryId,
11962                    'nc_terminal_type' => Configure::read('nc_terminal_type.pc')
11963                );    
11964                $decodeResp = json_decode($this->TeacherTextbookStat->avatarTextbookRating($params));
11965                $avatarTbRatings[$categoryId] = $decodeResp->teacher_textbook_rating;
11966            }
11967        }
11968        $this->set('avatarTbRatings', $avatarTbRatings);
11969        
11970        if(isset($this->request->data['sp']) && $this->request->data['sp']) {
11971            $this->set('avatar_sp', 1);
11972            $this->render('sp_teacher_badge_list');
11973        }
11974
11975    }    
11976
11977    /**
11978     * @api {post} /user/waiting/teacherOccupation teacherOccupation()
11979     * @apiName teacherOccupation
11980     * @apiGroup Waiting
11981     * @apiDescription Retrieves the occupation history of a specific teacher in Native Camp. It checks if the request is an AJAX request and returns the teacher occupation data.
11982     *
11983     * @apiBody {String} teacherId The ID of the teacher.
11984     * 
11985     * @apiSuccess {Object[]} teacherOccupation The teacher occupation data.
11986     * @apiSuccess {String} teacherOccupation.id The ID of the occupation detail.
11987     * @apiSuccess {String} teacherOccupation.teacher_id The ID of the teacher.
11988     * @apiSuccess {String} teacherOccupation.occupation The occupation of the teacher.
11989     * @apiSuccess {String} teacherOccupation.start_date The start date of the occupation.
11990     * @apiSuccess {String} teacherOccupation.end_date The end date of the occupation.
11991     * @apiSuccess {String} lang The language code for the page.
11992     *
11993     * @apiSuccessExample {json} Success-Response:
11994     *     {
11995     *         "teacherOccupation": [
11996     *             {
11997     *                 "id": "1",
11998     *                 "teacher_id": "123",
11999     *                 "occupation": "Software Engineer",
12000     *                 "start_date": "2020-01-01",
12001     *                 "end_date": "2021-01-01"
12002     *             },
12003     *             {
12004     *                 "id": "2",
12005     *                 "teacher_id": "123",
12006     *                 "occupation": "Project Manager",
12007     *                 "start_date": "2021-02-01",
12008     *                 "end_date": "2022-01-01"
12009     *             }
12010     *         ],
12011     *         "lang": "en"
12012     *     }
12013     *
12014     * @apiError {String} error Message indicating the error.
12015     *
12016     * @apiErrorExample {json} Error-Response:
12017     *     {
12018     *         "error": "Invalid request."
12019     *     }
12020     * 
12021     * @apiSampleRequest off
12022     */
12023    public function teacherOccupation() {
12024        $this->layout = "";
12025        if (!$this->request->is('ajax')) { return ; }
12026        
12027        $teacherId = $this->request->data['teacherId'];
12028        if (empty($teacherId)) { return ; }
12029
12030        //NC-9215 get teacher occupation history
12031        $teacherOccupation = ClassRegistry::init('TeacherOccupationDetail')->getTeacherOccupationDetails($teacherId);
12032        $this->set('teacherOccupation', $teacherOccupation);
12033        $lang = isset($this->localizeDir) ? $this->localizeDir : Configure::read('default.user_language');
12034        $this->set('lang', $lang);        
12035
12036        $this->render('teacher_occupation');
12037    }
12038
12039     //only used in this class controller
12040     //Retrieves the features of a specific teacher in Native Camp. It checks if the request is an AJAX request or if it is called from SP, and returns the teacher features data.
12041    public function teacherFeatures($sp = false, $teacherId = null) {
12042        $this->autoRender = false;
12043        $this->layout = false;
12044        if ($this->request->is('ajax') || $sp) {
12045            $teacherId = $this->request->data['teacherId'] ?? $teacherId;
12046            if (empty($teacherId)) { return ; }
12047    
12048            $feature = $this->TeacherFeature->find('first', array(
12049                'conditions' =>  array(
12050                    'TeacherFeature.teacher_id' => $teacherId
12051                )
12052            ));
12053            return json_encode(isset($feature['TeacherFeature']) ? $feature['TeacherFeature'] : array());
12054        } return;
12055    }
12056
12057    /**
12058     * @api {post} /user/waiting/getSelfReviews getSelfReviews()
12059     * @apiName getSelfReviews
12060     * @apiGroup Waiting
12061     * @apiDescription Retrieves the self-reviews for a specific teacher and user in Native Camp. It checks if the request is an AJAX request and returns the self-reviews data.
12062     *
12063     * @apiBody {String} teacherId The ID of the teacher.
12064     * @apiBody {String} userId The ID of the user.
12065     * 
12066     * @apiSuccess {Object[]} selfReviews The self-reviews data.
12067     * @apiSuccess {String} selfReviews.review The review text.
12068     * @apiSuccess {Number} selfReviews.rating The rating given by the user.
12069     * @apiSuccess {String} selfReviews.date The date of the review.
12070     * @apiSuccess {Number} selfLessonCount The count of lessons taken by the user with the teacher.
12071     * @apiSuccess {Number} daysPast The number of days past since the user's last lesson with the teacher.
12072     * @apiSuccess {String} lessonHistoryTeacherId The ID of the teacher for the lesson history.
12073     *
12074     * @apiSuccessExample {json} Success-Response:
12075     *     {
12076     *         "selfReviews": [
12077     *             {
12078     *                 "review": "Great lesson!",
12079     *                 "rating": 5,
12080     *                 "date": "2023-01-01"
12081     *             },
12082     *             {
12083     *                 "review": "Very helpful.",
12084     *                 "rating": 4,
12085     *                 "date": "2023-01-02"
12086     *             }
12087     *         ],
12088     *         "selfLessonCount": 5,
12089     *         "daysPast": 10,
12090     *         "lessonHistoryTeacherId": "123"
12091     *     }
12092     *
12093     * @apiError {String} error Message indicating the error.
12094     *
12095     * @apiErrorExample {json} Error-Response:
12096     *     {
12097     *         "error": "Invalid request."
12098     *     }
12099     * 
12100     * @apiSampleRequest off
12101     */
12102    public function getSelfReviews() {
12103        $this->layout = "";
12104        $this->autoRender = false;
12105        if (!$this->request->is('ajax')) { return ; }
12106        
12107        $teacherId = $this->request->data['teacherId'];
12108        if (empty($teacherId)) { return ; }
12109
12110        $userId = $this->request->data['userId'];
12111
12112        //get own reviews
12113        $selfReviews = array();
12114        $selfLessonCount = 0;
12115        $daysPast = 0;
12116        if ($userId) {
12117            $selfReviews = $this->getUserReviews($userId, $teacherId);
12118            $selfLessonCount = $this->LessonOnairsLog->countOwnLessons($userId, $teacherId);
12119            $daysPast = $this->LessonOnairsLog->countDaysPast($userId, $teacherId);
12120        }
12121
12122        $this->set('selfReviews', $selfReviews);
12123        $this->set('selfLessonCount', $selfLessonCount);
12124        $this->set('daysPast', $daysPast);
12125        $this->set('lessonHistoryTeacherId',$teacherId);
12126
12127        $this->render('/Elements/self_review');
12128    }
12129
12130    /**
12131     * @api {post} /user/waiting/getGenerationRating getGenerationRating()
12132     * @apiName getGenerationRating
12133     * @apiGroup Waiting
12134     * @apiDescription Retrieves the generation rating data for a specific teacher in Native Camp. It checks if the request is an AJAX request and returns the rating data.
12135     *
12136     * @apiBody {String} teacherId The ID of the teacher.
12137     * @apiBody {Boolean} [isAvatar] Indicates whether the teacher is an avatar.
12138     * 
12139     * @apiSuccess {Object} rates The generation rating data.
12140     * @apiSuccess {Number} rates.count The total number of ratings.
12141     * @apiSuccess {Number} rates.one_star The number of one-star ratings.
12142     * @apiSuccess {Number} rates.two_star The number of two-star ratings.
12143     * @apiSuccess {Number} rates.three_star The number of three-star ratings.
12144     * @apiSuccess {Number} rates.four_star The number of four-star ratings.
12145     * @apiSuccess {Number} rates.five_star The number of five-star ratings.
12146     * @apiSuccess {Object} rateBreakdown The breakdown of the generation rating data.
12147     * @apiSuccess {Number} rateBreakdown.weekly_average The weekly average rating.
12148     * @apiSuccess {Number} rateBreakdown.monthly_average The monthly average rating.
12149     * @apiSuccess {Number} rateBreakdown.total_average The total average rating.
12150     *
12151     * @apiSuccessExample {json} Success-Response:
12152     *     {
12153     *         "rates": {
12154     *             "count": 100,
12155     *             "one_star": 10,
12156     *             "two_star": 20,
12157     *             "three_star": 30,
12158     *             "four_star": 25,
12159     *             "five_star": 15
12160     *         },
12161     *         "rateBreakdown": {
12162     *             "weekly_average": 4.2,
12163     *             "monthly_average": 4.0,
12164     *             "total_average": 4.1
12165     *         }
12166     *     }
12167     *
12168     * @apiError {String} error Message indicating the error.
12169     *
12170     * @apiErrorExample {json} Error-Response:
12171     *     {
12172     *         "error": "Invalid request."
12173     *     }
12174     * 
12175     * @apiSampleRequest off
12176     */
12177    public function getGenerationRating() {
12178        $this->layout = "";
12179        $this->autoRender = false;
12180        
12181        if (!$this->request->is('ajax')) { return ; }
12182        
12183        $teacherId = Sanitize::escape($this->request->data['teacherId']);
12184        if (empty($teacherId)) { return ; }
12185
12186        $isAvatar = (isset($this->request->data['isAvatar']) && $this->request->data['isAvatar']) ? true : false;
12187        if($isAvatar){
12188            $teacherId = $this->Teacher->getAvatarTeacherId(array('avatar_id' => $teacherId));
12189            $rating = $this->UsersClassEvaluation->getRatings($avatarIds, true);
12190        }
12191
12192        $rating = $this->UsersClassEvaluation->getRatings($teacherId, true);
12193        if ($rating) {
12194            $rates = new UsersClassEvaluationTable($rating['UsersClassEvaluation']);
12195            $rateBreakdown = new UsersClassEvaluationTable($rating['TeacherWeeklyRating']);
12196        }
12197        $this->set('rates', $rates);        
12198        $this->set('rateBreakdown', $rateBreakdown);        
12199
12200        $this->render('teacher_generation_rating');
12201    }
12202
12203    /**
12204     * @api {post} /user/api/getGenerationRating getGenerationRatingAPI()
12205     * @apiName getGenerationRatingAPI
12206     * @apiGroup Waiting
12207     * @apiDescription Retrieves the generation rating data for a specific teacher in Native Camp. It checks the teacher ID and user token, and returns the rating data.
12208     *
12209     * @apiBody {String} teacher_id The ID of the teacher.
12210     * @apiBody {String} users_api_token The API token of the user.
12211     * 
12212     * @apiSuccess {Object} generationData The generation rating data. (0: 20, 1: 30, 2: 50)
12213     *
12214     * @apiSuccessExample {json} Success-Response:
12215     *     {
12216     *         "generationData": {
12217     *             "0": 20,
12218     *             "1": 30,
12219     *             "2": 50
12220     *         }
12221     *     }
12222     *
12223     * @apiError {Object} error The error details.
12224     * @apiError {String} error.id The error ID.
12225     * @apiError {String} error.message The error message.
12226     *
12227     * @apiErrorExample {json} Error-Response (Bad Request):
12228     *     {
12229     *         "error": {
12230     *             "id": "invalid_teacher_id",
12231     *             "message": "teacher_id is invalid"
12232     *         }
12233     *     }
12234      * @apiErrorExample {json} Error-Response (Unauthorized):
12235     *     {
12236     *         "error": {
12237     *             "id": "invalid_token",
12238     *             "message": "users_api_token is invalid"
12239     *         }
12240     *     }
12241     * 
12242     * @apiSampleRequest off
12243     */
12244    public function getGenerationRatingAPI(){
12245        $this->autoRender = false;
12246        $this->layout = false;
12247        $data = json_decode($this->request->input(), true);
12248        $teacherId = isset($data['teacher_id']) ? $data['teacher_id'] : '';
12249        if (empty($teacherId)) { 
12250            $response['error']['id'] = _('invalid_teacher_id');
12251            $response['error']['message'] = __('teacher_id is invalid');
12252            return json_encode($response);
12253        }
12254        $userToken = isset($data['users_api_token']) ? $data['users_api_token'] : '';
12255        $userData = $this->User->getUserDataByApiToken($userToken);
12256        if(!$userData) {
12257            $response['error']['id'] = _('invalid_token');
12258            $response['error']['message'] = __('users_api_token is invalid');
12259            return json_encode($response);
12260        }
12261        $rating = $this->UsersClassEvaluation->getRatings($teacherId, true);
12262        if ($rating) {
12263            $rates = new UsersClassEvaluationTable($rating['UsersClassEvaluation']);
12264            $rateBreakdown = new UsersClassEvaluationTable($rating['TeacherWeeklyRating']);
12265        }
12266        $ctr = 0;
12267        foreach($rates as $rate){
12268            $generationData[$ctr] = ($rate / $rates->count) * 100; // get percentages for data
12269            $ctr++;
12270        }
12271        //remove count element at the end
12272        array_pop($generationData);
12273        return json_encode($generationData);
12274    }
12275
12276    public function getUserMemo(){
12277        $this->autoRender = false;
12278        $this->layout = false;
12279        $data = json_decode($this->request->input(), true);
12280        $teacherId = isset($data['teacher_id']) ? $data['teacher_id'] : '';
12281        if (empty($teacherId)) { 
12282            $response['error']['id'] = _('invalid_teacher_id');
12283            $response['error']['message'] = __('teacher_id is invalid');
12284            return json_encode($response);
12285        }
12286        $userToken = isset($data['users_api_token']) ? $data['users_api_token'] : '';
12287        $userData = $this->User->getUserDataByApiToken($userToken);
12288        if(!$userData) {
12289            $response['error']['id'] = _('invalid_token');
12290            $response['error']['message'] = __('users_api_token is invalid');
12291            return json_encode($response);
12292        }
12293
12294        $getKeepMemo = $this->UsersMemo->find('first', array(
12295            'fields' => array(
12296                'id',
12297                'memo'
12298            ),
12299            'conditions' => array(
12300                'user_id' => $userData['id'],
12301                'teacher_id' => $teacherId,
12302                'type' => 0
12303            ),
12304            'order' => array('created DESC'),
12305        ));
12306        $memoData['id'] = $getKeepMemo['UsersMemo']['id'];
12307        $memoData['memo'] = $getKeepMemo['UsersMemo']['memo'];
12308        
12309        return json_encode($memoData);
12310    }
12311
12312    /**
12313     * @api {post} /user/waiting/getReservationCancellationBreakdown getReservationCancellationBreakdown()
12314     * @apiName getReservationCancellationBreakdown
12315     * @apiGroup Waiting
12316     * @apiDescription Retrieves the reservation and cancellation breakdown for a specific teacher in Native Camp. It checks if the request is an AJAX request and returns the reservation and cancellation data.
12317     *
12318     * @apiBody {String} teacherId The ID of the teacher.
12319     * 
12320     * @apiSuccess {Object} reserveAndCancel The reservation and cancellation breakdown data.
12321     * @apiSuccess {Number} reserveAndCancel.this_month_reserved The number of reservations made this month.
12322     * @apiSuccess {Number} reserveAndCancel.last_month_reserved The number of reservations made last month.
12323     * @apiSuccess {Number} reserveAndCancel.this_month_cancelled The number of reservations cancelled this month.
12324     * @apiSuccess {Number} reserveAndCancel.last_month_cancelled The number of reservations cancelled last month.
12325     * @apiSuccess {Number} reserveAndCancel.this_month_cancellation_rate The cancellation rate this month.
12326     * @apiSuccess {Number} reserveAndCancel.last_month_cancellation_rate The cancellation rate last month.
12327     * 
12328     * @apiSuccessExample {json} Success-Response:
12329     *     {
12330     *         "reserveAndCancel": {
12331     *             "this_month_reserved": 10,
12332     *             "last_month_reserved": 20,
12333     *             "this_month_cancelled": 5,
12334     *             "last_month_cancelled": 10,
12335     *             "this_month_cancellation_rate": 0.5
12336     *         }
12337     *     }
12338     *
12339     * @apiError {String} error Message indicating the error.
12340     *
12341     * @apiErrorExample {json} Error-Response:
12342     *     {
12343     *         "error": "Invalid request."
12344     *     }
12345     * 
12346     * @apiSampleRequest off
12347     */
12348    public function getReservationCancellationBreakdown() {
12349        $this->autoRender = false;
12350        $this->layout = false;
12351        if (!$this->request->is('ajax')) { return ; }
12352        
12353        $teacherId = $this->request->data['teacherId'];
12354        if (empty($teacherId)) { return ; }
12355
12356        //reservation and cancellation breakdown
12357        $reserveAndCancel = $this->getReserveAndCancelled($teacherId);
12358        return json_encode(isset($reserveAndCancel) ? $reserveAndCancel : array());
12359    }
12360
12361    // NJ-22649 transfer functionality from lesson-finish
12362    //not used function
12363    public function getActiveCampaign($params = array()) {
12364        $counseling_flg = (isset($params['counseling_flg']) && $params['counseling_flg']) ? true : false;
12365        $avatar_flg = (isset($params['avatar_flg']) && $params['avatar_flg']) ? true : false;
12366        $chat_hash = (isset($params['chat_hash']) && $params['chat_hash']) ? $params['chat_hash'] : '';
12367        $memberType = (isset($params['memberType']) && $params['memberType']) ? $params['memberType'] : 'student';
12368
12369        $campaignTerm = false;
12370        $modalCampaignType = '';
12371        $campaignPageRecord = '';
12372        $userId = $this->Auth->user('id');
12373        $userData = new UserTable($this->sharedUserData['User']);
12374
12375        $campaignSetting = ClassRegistry::init('CampaignSettingTable');
12376        $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12377        $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12378
12379        //Spring Callan Campaign
12380        $campaignSpringCallanPeriodFrom = Configure::read('campaign_config.callanFirstTime.period.start');
12381        $campaignSpringCallanPeriodTo = Configure::read('campaign_config.callanFirstTime.period.reservation_end');
12382        $campaignSpringCallan = $this->showCampaignModal($campaignSpringCallanPeriodFrom, $campaignSpringCallanPeriodTo);
12383
12384        //Campaign to talk with teachers from all over the world
12385        $campaignGlobalLesson = ClassRegistry::init('CampaignSettingTable')->globalLesson(array('user_id' => $userId, 'type' => 1)); //Check campaign duration date and if not sapuri user
12386        $sixthAnniv3Campaign = ClassRegistry::init('CampaignSettingTable')->sixthAnniv3(array('user_id' => $userId));
12387
12388        //Go to travel campaign
12389        $goToTravelDateArr = Configure::read('campaign_config.gototravel.period');
12390        $goToTravelCampaign = $this->showCampaignModal($goToTravelDateArr['start'], $goToTravelDateArr['end']);
12391
12392        //Alvark Collaboration Campaign
12393        $alvarkCollabCampaign = false;
12394        $alvarkCollabDateArr = Configure::read('campaign_config.alvark_collaboration.period');
12395        $alvarkCollabCheckDate = $this->showCampaignModal($alvarkCollabDateArr['start'], $alvarkCollabDateArr['end']);
12396        if (
12397            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.alvark_collaboration.valid_memberships')) 
12398            && $userData->currency_code == Configure::read('default.user_currency')
12399            && $alvarkCollabCheckDate
12400            && $this->localizeDir == Configure::read('default.user_language')
12401        ) {
12402            $alvarkCollabCampaign = true;
12403        }
12404
12405        // Campaign Settings Modal
12406        $currStr = $userData->currency_code;
12407        $langId = ClassRegistry::init("CountryCode")->getUserLanguageId($userData->native_language2);
12408        $today = date('Y-m-d H:i:s');
12409        $conditions = array(
12410            'user_plan_type' => $userData->getMembershipTypeIndex(),
12411            'plan_types' => Configure::read('campaign_settings.plan_types'),
12412            'is_sapuri_user' => $userData->isStudySapuri(),
12413            'corporate_user_types' => Configure::read('campaign_settings.corporates'),
12414            'free_user_type' => Configure::read('campaign_settings.free_user_type'),
12415        );
12416
12417        $campaignUserPlanType = $userData->getUserPlanType($conditions);
12418        $this->log("[CampaignSettingsModal][after_lesson] conditions -> " .  json_encode($conditions), "debug");
12419        $campaignSettings = null;
12420        if ((isset($campaignUserPlanType['plan_type']) && $campaignUserPlanType['plan_type']) &&
12421            (isset($campaignUserPlanType['user_type']) && $campaignUserPlanType['user_type'])
12422        ) {
12423            $campaignSettingsModel = ClassRegistry::init('CampaignSettings');
12424            $campaignSettings = $campaignSettingsModel->getActiveAndNotEnded(array(
12425                'fields' => array(
12426                    'CampaignSettings.id',
12427                    'CampaignSettings.modal_html',
12428                    'CampaignSettings.pc_url',
12429                    'CampaignSettings.image_url_pc'
12430                ),
12431                'conditions' => array(
12432                    'CampaignSettings.promo_end >=' => $today,
12433                    'CampaignSettings.status_flag' => 1,
12434                    'CampaignSettings.promo_event_type' => 1, // after lesson
12435                    'CampaignSettings.pc_url IS NOT NULL',
12436
12437                    // os
12438                    array(
12439                        'OR' => array(
12440                            array('CampaignSettings.promo_os LIKE' => '%1%'), // pc
12441                            array('CampaignSettings.promo_os LIKE' => '%0%'), // all
12442                        )
12443                    ),
12444
12445                    // login status
12446                    array(
12447                        'OR' => array(
12448                            array('CampaignSettings.promo_login_status LIKE' => '%1%'), // sign in
12449                            array('CampaignSettings.promo_login_status LIKE' => '%0%'), // all
12450                        )
12451                    ),
12452
12453                    // Plan type
12454                    array(
12455                        'OR' => array(
12456                            array('CampaignSettings.promo_plan_type LIKE' => '%'.$campaignUserPlanType['plan_type'].'%'),
12457                            array('CampaignSettings.promo_plan_type LIKE' => '%0%'), // ALL
12458                        )
12459                    ),
12460
12461                    // User type
12462                    array(
12463                        'OR' => array(
12464                            array('CampaignSettings.promo_user_type LIKE' => '%'.$campaignUserPlanType['user_type'].'%'),
12465                            array('CampaignSettings.promo_user_type LIKE' => '%0%') // ALL
12466                        )
12467                    ),
12468
12469                    // Currency and Language
12470                    array(
12471                        "(SELECT COUNT(*) FROM `campaign_setting_currency` WHERE `CampaignSettings`.`id` = `campaign_setting_currency`.`campaign_setting_id` AND `campaign_setting_currency`.`currency_code` = '".$currStr."') > 0"
12472                    ),
12473                    array(
12474                        "(SELECT COUNT(*) FROM `campaign_setting_language` WHERE `CampaignSettings`.`id` = `campaign_setting_language`.`campaign_setting_id` AND `campaign_setting_language`.`language_id` = '".$langId."') > 0"
12475                    )
12476                ),
12477                'order' => 'CampaignSettings.promo_start ASC'
12478            ));
12479        }
12480
12481        //Marines Collaboration Campaign
12482        $marinesCollabCampaign = false;
12483        $marinesCollabDateArr = Configure::read('campaign_config.going_global_marines_collaboration.period');
12484        $marinesCollabCheckDate = $this->showCampaignModal($marinesCollabDateArr['start'], $marinesCollabDateArr['end']);
12485        if (
12486            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.going_global_marines_collaboration.valid_memberships')) 
12487            && $marinesCollabCheckDate
12488            && $this->localizeDir == Configure::read('default.user_language')
12489        ) {
12490            $marinesCollabCampaign = true;
12491        }
12492
12493        // //Daily News Campaign
12494        // $dailyNewsCampaign = false;
12495        // $dailyNewsDateArr = Configure::read('campaign_config.daily_news.period');
12496        // $dailyNewsCheckDate = $this->showCampaignModal($dailyNewsDateArr['start'], $dailyNewsDateArr['end']);
12497        // if (
12498        //     in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.daily_news.valid_memberships')) 
12499        //     && $dailyNewsCheckDate
12500        // ) {
12501        //     $dailyNewsCampaign = true;
12502        // }
12503
12504        //Favorite Teacher Campaign
12505        $favoriteTeacherCampaign = false;
12506        $favoriteTeacherDateArr = Configure::read('campaign_config.favorite_teacher.period');
12507        $favoriteTeacherCheckDate = $this->showCampaignModal($favoriteTeacherDateArr['start'], $favoriteTeacherDateArr['end']);
12508        if (
12509            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.favorite_teacher.valid_memberships')) 
12510            && $favoriteTeacherCheckDate
12511        ) {
12512            $favoriteTeacherCampaign = true;
12513        }
12514
12515        //Family Plan Campaign
12516        $familyPlanCampaign = false;
12517        $familyPlanDateArr = Configure::read('campaign_config.family_plan.period');
12518        $familyPlanCheckDate = $this->showCampaignModal($familyPlanDateArr['start'], $familyPlanDateArr['end']);
12519        if (
12520            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.family_plan.valid_memberships')) 
12521            && $familyPlanCheckDate
12522        ) {
12523            $familyPlanCampaign = true;
12524        }
12525
12526        //Christmas Campaign
12527        $christmasCampaign = false;
12528        $christmasDateArr = Configure::read('campaign_config.christmas.period');
12529        $christmasCheckDate = $this->showCampaignModal($christmasDateArr['start'], $christmasDateArr['end']);
12530        if (
12531            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.christmas.valid_memberships')) 
12532            && $christmasCheckDate
12533        ) {
12534            $christmasCampaign = true;
12535        }
12536
12537        //New year Part 1 Campaign
12538        $newYearPart1Campaign = false;
12539        $newYearPart1DateArr = Configure::read('campaign_config.new_year_part_1.period');
12540        $newYearPart1CheckDate = $this->showCampaignModal($newYearPart1DateArr['start'], $newYearPart1DateArr['end']);
12541        if (
12542            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.new_year_part_1.valid_memberships')) 
12543            && ($userData->admin_flg || $newYearPart1CheckDate) 
12544            && $this->localizeDir == Configure::read('default.user_language')
12545        ) {
12546            $newYearPart1Campaign = true;
12547        }
12548
12549        //New grammar Campaign
12550        $newGrammarCampaign = false;
12551        $newGrammarDateArr = Configure::read('campaign_config.new_grammar.period');
12552        $newGrammarCheckDate = $this->showCampaignModal($newGrammarDateArr['start'], $newGrammarDateArr['end']);
12553        if (
12554            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.new_grammar.valid_memberships')) 
12555            && $newGrammarCheckDate
12556        ) {
12557            $newGrammarCampaign = true;
12558        }
12559
12560        //Alvark collab Campaign
12561        $alvarkCollab2Campaign = false;
12562        $alvarkCollab2DateArr = Configure::read('campaign_config.alvark_collab_2.period');
12563        $alvarkCollab2CheckDate = $this->showCampaignModal($alvarkCollab2DateArr['start'], $alvarkCollab2DateArr['end']);
12564        if (
12565            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.alvark_collab_2.valid_memberships')) 
12566            && $alvarkCollab2CheckDate
12567            && $this->localizeDir == Configure::read('default.user_language')
12568        ) {
12569            $alvarkCollab2Campaign = true;
12570        }
12571
12572        //Golden Week NC Campaign
12573        $goldenWeekNCChallengeCampaign = false;
12574        $goldenWeekNCChallengeDateArr = Configure::read('campaign_config.golden_week_nc_challenge.period');
12575        $goldenWeekNCChallengeCheckDate = $this->showCampaignModal($goldenWeekNCChallengeDateArr['start'], $goldenWeekNCChallengeDateArr['end']);
12576        if (
12577            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.golden_week_nc_challenge.valid_memberships')) 
12578            && $goldenWeekNCChallengeCheckDate
12579        ) {
12580            $goldenWeekNCChallengeCampaign = true;
12581        }
12582
12583        if ($campaignSpringCallan) {
12584            $campaignTerm = $campaignSpringCallan;
12585            $modalCampaignType = 'campaign_callan_half_spring';
12586            $campaignPageRecord = 'callan_half_spring_record';
12587            // check if not a sapuri student
12588            $userData = new UserTable( $this->sharedUserData[ 'User' ] );
12589            if (in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.callanFirstTime.membership'))) {        
12590                /* count callan lesson taken within the campaign period */
12591                $countCallanLesson = ClassRegistry::init('CampaignSettingTable')->callanMarathonCampaign(array(
12592                    'user_id' => $this->Auth->user("id"),
12593                    'date_period' => array(
12594                            Configure::read('campaign_config.callanFirstTime.period.start'),
12595                            Configure::read('campaign_config.callanFirstTime.period.reservation_end')
12596                        ),
12597                    'tb_category_id' => Configure::read('campaign_config.callanFirstTime.textbook_category')
12598                ));
12599                $response['countCallanLesson'] = $countCallanLesson;
12600            }
12601
12602        } else if ($campaignGlobalLesson) {
12603            //If not counseling: display modal stamp
12604            if (!$counseling_flg) {
12605                $campaignTerm = $campaignGlobalLesson;
12606                $modalCampaignType = 'campaign_global_lesson';
12607                $campaignPageRecord = 'global_lesson_record';
12608            }
12609        } else if ($sixthAnniv3Campaign) {
12610            $campaignTerm = $sixthAnniv3Campaign;
12611            $modalCampaignType = 'campaign_sixth_anniv_3';
12612            $campaignPageRecord = 'sixth_anniv_record';
12613
12614        //Go to travel campaign
12615        } else if ($goToTravelCampaign) {
12616            if (!$counseling_flg) {
12617                $userData = new UserTable( $this->sharedUserData[ 'User' ] );
12618                $stampAchieved = array();
12619                if (!in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.gototravel.membership_invalid'))) {
12620                    // get student achieved lesson stamps
12621                    $stampAchieved = ClassRegistry::init('CampaignSettingTable')->camapaignGoToTravelTbStamp(array(
12622                        'user_id' => $this->Auth->user( 'id' ),
12623                        'start_time' => Configure::read('campaign_config.gototravel.period.start'),
12624                        'end_time' => Configure::read('campaign_config.gototravel.period.end'),
12625                        'tb_connect_ids' => array_values(array_flip(Configure::read('campaign_config.gototravel.textbook_connect'))),
12626                        'lesson_min_time' => Configure::read('campaign_config.gototravel.lesson_time')
12627                    ));
12628                    $stampAchieved = is_array($stampAchieved) ? array_values($stampAchieved) : $stampAchieved;
12629                    $response['stampAchieved'] = $stampAchieved;
12630                    $modalCampaignType = 'campaign_gototravel_is_back';
12631                    $campaignPageRecord = 'gototravel_is_back_record';
12632                    $campaignTerm = $goToTravelCampaign;
12633                }
12634            }
12635        } else if ($alvarkCollabCampaign) {
12636            if (!$counseling_flg) {
12637                $cst = ClassRegistry::init('CampaignSettingTable');
12638                $campaignStamps = $cst->alvarkCollaboration(
12639                    array(
12640                        'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12641                        'type' => 1,
12642                    )
12643                );
12644                $response['campaignStamps'] = $campaignStamps;
12645                $modalCampaignType = 'campaign_going_global_alvark_live';
12646                $campaignTerm = $alvarkCollabCampaign;
12647            }
12648        } 
12649
12650        if ($campaignSettings) {
12651            $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12652            $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12653            $showCampaignSettingsCampModal = array();
12654            foreach ($campaignSettings as $key => $value) {
12655                $id = $value['CampaignSettings']['id'];
12656                if (!in_array($id, $dontShowCampaignModals)) {
12657                    $showCampaignSettingsCampModal[] = $id;
12658                }
12659            }
12660            $response['campaignSettings'] = $campaignSettings;
12661            $response['showCampaignSettingsCampModal'] = $showCampaignSettingsCampModal;
12662            $response['campaignSettingsAfterLeson'] = true;
12663        } else if ($marinesCollabCampaign) {
12664            if (!$counseling_flg) {
12665                $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12666                $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12667                $marinesCollabCampPeriod = Configure::read('campaign_config.going_global_marines_collaboration.period');
12668                $marinesCollabCampaignSettingId = Configure::read('campaign_config.going_global_marines_collaboration.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12669    
12670                $response['marinesCollabCampaignSettingId'] = $marinesCollabCampaignSettingId;
12671                $response['marinesCollabCampaign'] = $marinesCollabCampaign;
12672                $response['showMarinesCollabCampModal'] = (!in_array($marinesCollabCampaignSettingId, $dontShowCampaignModals)) ? true : false;
12673
12674                $cst = ClassRegistry::init('CampaignSettingTable');
12675                $campaignStamps = $cst->marinesCollaboration(
12676                    array(
12677                        'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12678                        'type' => 1,
12679                        'display_type' => 1,
12680                    )
12681                );
12682                $response['campaignStamps'] = $campaignStamps;
12683                $modalCampaignType = 'campaign_going_global_marines_live';
12684                $campaignTerm = $marinesCollabCampaign;
12685            }
12686        }
12687        // if ($dailyNewsCampaign) {
12688        //     if (!$counseling_flg) {
12689        //         $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12690        //         $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12691        //         $dailyNewsCampaignSettingId = Configure::read('campaign_config.daily_news.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12692
12693        //         $response['dailyNewsCampaignSettingId'] = $dailyNewsCampaignSettingId;
12694        //         $response['dailyNewsCampaign'] = $dailyNewsCampaign;
12695        //         $response['showDailyNewsCampModal'] = (!in_array($dailyNewsCampaignSettingId, $dontShowCampaignModals)) ? true : false;
12696
12697        //         $cst = ClassRegistry::init('CampaignSettingTable');
12698        //         $campaignStamps = $cst->dailyNews(
12699        //             array(
12700        //                 'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12701        //                 'type' => 1
12702        //             )
12703        //         );
12704        //         $response['campaignStamps'] = $campaignStamps;
12705        //         $modalCampaignType = 'campaign_dailynews_live';
12706        //         $campaignTerm = $dailyNewsCampaign;
12707        //     }
12708        // }
12709
12710        if ($favoriteTeacherCampaign) {
12711            if (!$counseling_flg) {
12712                $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12713                $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12714                $favoriteTeacherCampaignSettingId = Configure::read('campaign_config.favorite_teacher.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12715
12716                $response['favoriteTeacherCampaignSettingId'] = $favoriteTeacherCampaignSettingId;
12717                $response['favoriteTeacherCampaign'] = $favoriteTeacherCampaign;
12718                $response['showFavoriteTeacherCampModal'] = (!in_array($favoriteTeacherCampaignSettingId, $dontShowCampaignModals)) ? true : false;
12719
12720                $cst = ClassRegistry::init('CampaignSettingTable');
12721                $campaignStamps = $cst->favoriteTeacher(
12722                    array(
12723                        'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12724                        'type' => 1,
12725                        'requested_events' => array(1)
12726                    )
12727                );
12728                $response['campaignStamps'] = $campaignStamps['event1'];
12729                $modalCampaignType = 'campaign_favorite_teachers_live';
12730                $campaignTerm = $favoriteTeacherCampaign;
12731            }
12732        }
12733
12734        if ($familyPlanCampaign) {
12735            if (!$counseling_flg) {
12736                $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12737                $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12738                $familyPlanCampaignSettingId = Configure::read('campaign_config.family_plan.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12739
12740                $response['familyPlanCampaignSettingId'] = $familyPlanCampaignSettingId;
12741                $response['familyPlanCampaign'] = $familyPlanCampaign;
12742                $response['showFamilyPlanCampModal'] = (!in_array($familyPlanCampaignSettingId, $dontShowCampaignModals)) ? true : false;
12743
12744                $cst = ClassRegistry::init('CampaignSettingTable');
12745                $lessonLogsFPC = $cst->familyPlan(
12746                    array(
12747                        'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12748                        'type' => 1
12749                    )
12750                );
12751                $response['lessonLogsFPC'] = $lessonLogsFPC;
12752                $modalCampaignType = 'campaign_plan_family_live';
12753                $campaignTerm = $familyPlanCampaign;
12754            }
12755        }
12756
12757        if ($christmasCampaign) {
12758            if (!$counseling_flg) {
12759                $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12760                $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12761                $christmasCampaignSettingId = Configure::read('campaign_config.christmas.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12762
12763                $response['christmasCampaignSettingId'] = $christmasCampaignSettingId;
12764                $response['christmasCampaign'] = $christmasCampaign;
12765                $response['showChristmasCampModal'] = (!in_array($christmasCampaignSettingId, $dontShowCampaignModals)) ? true : false;
12766
12767                $cst = ClassRegistry::init('CampaignSettingTable');
12768                $lessonStamps = $cst->christmas(
12769                    array(
12770                        'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12771                        'type' => 1,
12772                    )
12773                );
12774                $response['lessonStamps'] = $lessonStamps;
12775                $modalCampaignType = 'campaign_christmas_live';
12776                $campaignTerm = $christmasCampaign;
12777            }
12778        }
12779
12780        if ($newYearPart1Campaign) {
12781            $campaignID = Configure::read('campaign_config.new_year_part_1.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_login');
12782            $lotteryData = array();
12783            $cst = ClassRegistry::init('CampaignSettingTable');
12784            $newYearLessonData = $cst->checkLastLesson(
12785                array(
12786                    'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12787                    'chat_hash' => $chat_hash,
12788                    'campaign_id' => $campaignID[0]
12789                )
12790            );
12791            $response['newYearPart1Campaign'] = $newYearPart1Campaign;
12792            $response['showNewYearPart1CampModal'] = ($newYearLessonData) ? true : false;
12793            $modalCampaignType = ($newYearLessonData) ? 'campaign_new_year_afterlesson' : '';
12794            $campaignTerm = $newYearPart1Campaign;
12795        }
12796
12797        if ($newGrammarCampaign) {
12798            if (!$counseling_flg) {
12799                $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12800                $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12801                $newGrammarCampaignSettingId = Configure::read('campaign_config.new_grammar.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12802    
12803                $response['newGrammarCampaignSettingId'] = $newGrammarCampaignSettingId;
12804                $response['newGrammarCampaign'] = $newGrammarCampaign;
12805                $response['showNewGrammarCampAfterLessonModal'] = (!in_array($newGrammarCampaignSettingId, $dontShowCampaignModals)) ? true : false;
12806
12807                $cst = ClassRegistry::init('CampaignSettingTable');
12808                $campaignStamps = $cst->newGrammar(
12809                    array(
12810                        'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12811                        'type' => 1
12812                    )
12813                );
12814                $response['campaignStamps'] = $campaignStamps;
12815                $modalCampaignType = 'campaign_newgrammar_live';
12816                $campaignTerm = $newGrammarCampaign;
12817            }
12818        }
12819
12820        if ($alvarkCollab2Campaign) {
12821            if (!$counseling_flg) {
12822                $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12823                $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12824                $alvarkCollab2CampaignSettingId = Configure::read('campaign_config.alvark_collab_2.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12825    
12826                $response['alvarkCollab2CampaignSettingId'] = $alvarkCollab2CampaignSettingId;        
12827                $response['alvarkCollab2Campaign'] = $alvarkCollab2Campaign;
12828                $response['showAlvarkCollab2CampAfterLessonModal'] = (!in_array($alvarkCollab2CampaignSettingId, $dontShowCampaignModals)) ? true : false;    
12829
12830                $cst = ClassRegistry::init('CampaignSettingTable');
12831                $avk2coupon = $cst->alvarkCollab2(
12832                    array(
12833                        'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12834                        'type' => 1
12835                    )
12836                );
12837                $response['avk2coupon'] = $avk2coupon;
12838                $modalCampaignType = 'mypage_going_global_alvark_live';
12839                $campaignTerm = $alvarkCollab2Campaign;
12840            }
12841        }
12842
12843        if ($goldenWeekNCChallengeCampaign) {
12844            if (!$counseling_flg) {
12845                $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12846                $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12847                $campModalSettingIDs = Configure::read('campaign_config.golden_week_nc_challenge.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings');
12848                $goldenWeekNCChallengeCampaignSettingId = ($memberType == 'student') ? $campModalSettingIDs['after_lesson'] : $campModalSettingIDs['after_live_lesson_viewer'];
12849
12850                $cst = ClassRegistry::init('CampaignSettingTable');
12851                $check = $cst->checkGoldenWeekChallengeModals(array(
12852                    'user_id' => $userData->id,
12853                    'chat_hash' => $chat_hash,
12854                    'camp_setting_id' => $goldenWeekNCChallengeCampaignSettingId
12855                ));
12856
12857                //Get stamp
12858                $goldenWeekNCChallengeStamp = $cst->goldenWeekChallenge(
12859                    array(
12860                        'user_id' => $userData->id,
12861                        'type' => 1,
12862                        'challenge_stamp' => ($memberType == 'student') ? 3 : 2
12863                    )
12864                );
12865
12866                $displayModalAfterLesson = (!in_array($goldenWeekNCChallengeCampaignSettingId, $dontShowCampaignModals) && $check) ? true : false;
12867                
12868                $response['goldenWeekNCChallengeStamp'] = $goldenWeekNCChallengeStamp;
12869                $response['goldenWeekNCChallengeCampaignSettingId'] = $goldenWeekNCChallengeCampaignSettingId;
12870                $response['goldenWeekNCChallengeCampaignAfterLesson'] = $goldenWeekNCChallengeCampaign;
12871                $response['showGoldenWeekNCChallengeCampAfterLessonModal'] = $displayModalAfterLesson;
12872
12873                $modalCampaignType = ($memberType == 'student') ? 'campaign_golden_week_lesson' : 'campaign_golden_week_live';
12874                $modalCampaignType = ($displayModalAfterLesson) ? $modalCampaignType : '';
12875                $campaignTerm = $goldenWeekNCChallengeCampaign;
12876            }
12877        }
12878
12879
12880        //NJ-21995 Super native camp festival campaign
12881        $superNativeCamp = array(
12882            'campaign' => 'super_native_camp',
12883            'user_membership' => $userData->getMembershipTypeIndex()
12884        );
12885        if(!$counseling_flg && $campaignSetting->campaignChecker($superNativeCamp)){
12886            $campModalSettingIDs = Configure::read('campaign_config.super_native_camp.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings');
12887            $superNativeCampFestivalCampSettingID = $campModalSettingIDs['after_lesson'];
12888            $campaignTotalMinsOfLesson = $campaignSetting->superNativeCampFestival(array('user_id' => $userData->id, 'type' => 1));
12889            $checkCampaignLesson = $campaignSetting->superNativeCampFestival(array('user_id' => $userData->id, 'type' => 3, 'chat_hash' => $chat_hash));
12890            $displayModalAfterLesson = (!in_array($superNativeCampFestivalCampSettingID, $dontShowCampaignModals) && $checkCampaignLesson) ? true : false;;
12891            $response['campaignTotalMinsOfLesson'] = $campaignTotalMinsOfLesson;
12892            $response['superNativeCampFestivalCampSettingID'] = $superNativeCampFestivalCampSettingID;
12893            $response['showSuperNativeCampFestivalCampAfterLessonModal'] = $displayModalAfterLesson;
12894
12895            $modalCampaignType = 'campaign_nc_festival_live';
12896            $campaignTerm = true;
12897        }
12898
12899        //NJ-25217 Online English Conversation No.1 Festival
12900        $camp_OECF = array(
12901            'campaign' => 'OECF',
12902            'user_membership' => $userData->getMembershipTypeIndex(),
12903            'allow_language' => array(Configure::read('default.user_language'), 'en'),
12904            'user_language' => ($this->localizeDir == Configure::read('default.user_language') && in_array($userData->native_language2, array(Configure::read('default.user_language'), 'en'))) ? Configure::read('default.user_language') : $this->localizeDir,
12905            'user_currency' => $userData->currency_code,
12906            'allow_currency' => ($userData->native_language2 == 'en') ? array(Configure::read('default.user_currency')) : null
12907        );
12908        if(!$counseling_flg && $campaignSetting->campaignChecker($camp_OECF)){
12909            $campModalSettingIDs = Configure::read('campaign_config.OECF.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings');
12910            $camp_OECF_setting_ID = $campModalSettingIDs['after_lesson'][0];
12911            $dataStamp = $campaignSetting->onlineEnglishConversationFestival(array('user_id' => $userData->id, 'type' => 1, 'device' => 1));
12912            $displayModalAfterLesson = (!in_array($camp_OECF_setting_ID, $dontShowCampaignModals)) ? true : false;
12913            $response['dataStamp'] = $dataStamp;
12914            $response['OECFCampSettingID'] = $camp_OECF_setting_ID;
12915            $response['showOECFCampAfterLessonModal'] = $displayModalAfterLesson;
12916
12917            $modalCampaignType = 'campaign_nc_no1_festival_live';
12918            $campaignTerm = true;
12919        }
12920
12921        // - NJ-31307 Callan Unlimited Campaign
12922        $camp_callan_unlimited = array(
12923            'campaign' => 'callan_unlimited',
12924            'user_membership' => $userData->getMembershipTypeIndex()
12925        );
12926        if(!$counseling_flg && $campaignSetting->campaignChecker($camp_callan_unlimited)){
12927            $camp_callan_unlimited_ID = Configure::read('campaign_config.callan_unlimited.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12928            $displayModalAfterLesson = (!in_array($camp_callan_unlimited_ID, $dontShowCampaignModals)) ? true : false;
12929            if($displayModalAfterLesson){
12930                $modalCampaignType = 'campaign_callan_unlimited_afterlesson';
12931                $campaignTerm = true;
12932            }
12933        }
12934
12935        // - NJ-32989 : New Year Lottery Campaign
12936        $camp_new_year_lottery = array(
12937            'campaign' => 'new_year_lottery',
12938            'user_membership' => $userData->getMembershipTypeIndex(),
12939            'user_language' => $userData->native_language2,
12940            'allow_language' => Configure::read('campaign_config.new_year_lottery.allow_languages'),
12941            'user_currency' => $userData->currency_code,
12942            'other_validation' => true,
12943        );
12944        if($campaignSetting->campaignChecker($camp_new_year_lottery)){
12945            $camp_new_year_lottery_ID = Configure::read('campaign_config.new_year_lottery.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12946            $displayModalAfterLesson = (!in_array($camp_new_year_lottery_ID[0], $dontShowCampaignModals)) ? true : false;
12947            if($displayModalAfterLesson){
12948                $modalCampaignType = 'campaign_new_year_afterlesson';
12949                $campaignTerm = true;
12950            }
12951        }
12952
12953        // - NJ-32989 Around the world campaign
12954        $camp_around_the_world = array(
12955            'campaign' => 'around_the_world',
12956            'user_membership' => $userData->getMembershipTypeIndex(),
12957            'user_currency' => $userData->currency_code,
12958            'allow_currency' => Configure::read('campaign_config.around_the_world.allow_currencies'),
12959            'user_language' => $userData->native_language2,
12960            'allow_language' => Configure::read('campaign_config.around_the_world.allow_languages'),
12961        );
12962        if(!$counseling_flg && $campaignSetting->campaignChecker($camp_around_the_world)){
12963            $camp_around_the_world_ID = Configure::read('campaign_config.around_the_world.modal_settings.after_lesson');
12964            $displayModalAfterLesson = (!in_array($camp_around_the_world_ID, $dontShowCampaignModals)) ? true : false;
12965            if($displayModalAfterLesson){
12966                $modalCampaignType = 'campaign_around_the_world_afterlesson';
12967                $campaignTerm = true;
12968            }
12969        }
12970
12971        // - NJ-36818 : What are you doing now? Native Camp! Campaign
12972        $camp_spare_time = array(
12973            'campaign' => 'spare_time_march',
12974            'user_membership' => $userData->getMembershipTypeIndex(),
12975            'user_language' => $userData->native_language2,
12976            'allow_language' => Configure::read('campaign_config.spare_time_march.allow_languages'),
12977        );
12978        if(!$counseling_flg && $campaignSetting->campaignChecker($camp_spare_time)){
12979            $camp_spare_time_ID = Configure::read('campaign_config.spare_time_march.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12980            $displayModalAfterLesson = (!in_array($camp_spare_time_ID, $dontShowCampaignModals)) ? true : false;
12981            if($displayModalAfterLesson){
12982                $modalCampaignType = 'campaign_spare_time_afterlesson';
12983                $campaignTerm = true;
12984            }
12985        }
12986
12987        // - NJ-39740 : 1.5 Million - Thank You Campaign
12988        $camp_opfm = array(
12989            'campaign' => 'OPFM_campaign',
12990            'user_membership' => $userData->getMembershipTypeIndex(),
12991            'user_language' => $userData->native_language2,
12992            'allow_language' => Configure::read('campaign_config.OPFM_campaign.allow_languages'),
12993        );
12994        if(!$counseling_flg && $campaignSetting->campaignChecker($camp_opfm)){
12995            $camp_opfm_ID = Configure::read('campaign_config.OPFM_campaign.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12996            $displayModalAfterLesson = (!in_array($camp_opfm_ID, $dontShowCampaignModals)) ? true : false;
12997            if($displayModalAfterLesson){
12998                $modalCampaignType = 'campaign_150_ten_thousand_afterlesson';
12999                $campaignTerm = true;
13000            }
13001        }
13002
13003        // - NJ-42488 : kakaku_01 campaign
13004        $camp_kakaku01 = array(
13005            'campaign' => 'kakaku_01',
13006            'user_membership' => $userData->getMembershipTypeIndex(),
13007        );
13008        if(!$counseling_flg && $campaignSetting->campaignChecker($camp_kakaku01)){
13009            $camp_kakaku_01_IDs = Configure::read('campaign_config.kakaku_01.modal_settings.after_lesson');
13010            if($userData->native_language2 == Configure::read('default.user_language')){
13011                $displayModalAfterLesson = (!in_array($camp_kakaku_01_IDs[0], $dontShowCampaignModals)) ? true : false;
13012                if($displayModalAfterLesson){
13013                    $modalCampaignType = 'campaign_kakaku_01_live';
13014                    $campaignTerm = true;
13015                }
13016            } else {
13017                $displayModalAfterLesson = (!in_array($camp_kakaku_01_IDs[1], $dontShowCampaignModals)) ? true : false;
13018                if($displayModalAfterLesson){
13019                    $modalCampaignType = 'campaign_dailynews_live';
13020                    $campaignTerm = true;
13021                }
13022            }
13023        }
13024
13025        // - NJ-45886 [Campaign] AI Speaking Campaign
13026        $camp_ai_speaking_sept = array(
13027            'campaign' => 'ai_speaking_sept',
13028            'user_membership' => $userData->getMembershipTypeIndex(),
13029            'user_language' => $userData->native_language2,
13030            'allow_language' => Configure::read('campaign_config.ai_speaking_sept.allow_languages'),
13031        );
13032        if(!$counseling_flg && $campaignSetting->campaignChecker($camp_ai_speaking_sept)){
13033            $camp_ai_speaking_sept_IDs = Configure::read('campaign_config.ai_speaking_sept.modal_settings.after_lesson');
13034            $displayModalAfterLesson = (!in_array($camp_ai_speaking_sept_IDs[0], $dontShowCampaignModals)) ? true : false;
13035            if($displayModalAfterLesson){
13036                $modalCampaignType = 'campaign_speaking_afterlesson';
13037                $campaignTerm = true;
13038            }
13039        }
13040
13041        //NJ-50048 Lesson coin gift campaign
13042        $lessonCoinGiftCamp = array(
13043            'campaign' => 'taking_lesson_and_continue_plan',
13044            'user_membership' => $userData->getMembershipTypeIndex(),
13045            'allow_language' => Configure::read('campaign_config.taking_lesson_and_continue_plan.allowed_languages'),
13046            'user_language' => $userData->native_language2,
13047        );
13048        if(!$counseling_flg && $campaignSetting->campaignChecker($lessonCoinGiftCamp)){
13049            $campModalSettingIDs = Configure::read('campaign_config.taking_lesson_and_continue_plan.modal_settings');
13050            $lessonCoinGiftCampSettingID = $campModalSettingIDs['after_lesson'];
13051            $displayModalAfterLesson = (!in_array($lessonCoinGiftCampSettingID, $dontShowCampaignModals)) ? true : false;
13052            if($displayModalAfterLesson){
13053                $modalCampaignType = 'campaign_lesson_coin_gift_live';
13054                $campaignTerm = true;
13055            }
13056        }
13057
13058        //NJ-55569 2025 New Year Campaign
13059        $newYearCamp = array(
13060            'campaign' => 'newyear_2025',
13061            'user_membership' => $userData->getMembershipTypeIndex(),
13062            'allow_language' => Configure::read('campaign_config.newyear_2025.allowed_languages'),
13063            'user_language' => $userData->native_language2,
13064            'allow_currency' => Configure::read('campaign_config.newyear_2025.allowed_currencies'),
13065            'user_currency' => $userData->currency_code,
13066        );
13067        if(!$counseling_flg && $campaignSetting->campaignChecker($newYearCamp)){
13068            $campModalSettingIDs = Configure::read('campaign_config.newyear_2025.modal_settings');
13069            $newYearCampSettingID = $campModalSettingIDs['after_lesson'];
13070            if($userData->native_language2 == Configure::read('default.user_language')){
13071                $displayModalAfterLesson = (!in_array($newYearCampSettingID[0], $dontShowCampaignModals)) ? true : false;
13072                if($displayModalAfterLesson){
13073                    $modalCampaignType = 'campaign_new_year_live';
13074                    $campaignTerm = true;
13075                }
13076            } else {
13077                $displayModalAfterLesson = (!in_array($newYearCampSettingID[1], $dontShowCampaignModals)) ? true : false;
13078                if($displayModalAfterLesson){
13079                    $modalCampaignType = 'campaign_dailynews_live';
13080                    $campaignTerm = true;
13081                }
13082            }
13083        }
13084
13085        //NJ-59889 3 Million Campaign
13086        $threeMillionCamp = array(
13087            'campaign' => '3_million',
13088            'user_membership' => $userData->getMembershipTypeIndex(),
13089            'allow_language' => Configure::read('campaign_config.3_million.allowed_languages'),
13090            'user_language' => $userData->native_language2,
13091            'allow_currency' => Configure::read('campaign_config.3_million.allowed_currencies'),
13092            'user_currency' => $userData->currency_code,
13093        );
13094        if(!$counseling_flg && $campaignSetting->campaignChecker($threeMillionCamp)){
13095            $threeMillionCampSettingId = Configure::read('campaign_config.3_million.modal_settings.after_lesson');
13096            $displayModalAfterLesson = (!in_array($threeMillionCampSettingId, $dontShowCampaignModals)) ? true : false;
13097            if($displayModalAfterLesson){
13098                $modalCampaignType = 'campaign_3_million_afterlesson';
13099                $campaignTerm = true;
13100            }
13101        }
13102
13103        // - NJ-65066 【Campaign】Daily Topics
13104        $dailytopicsCamp = array(
13105            'campaign' => 'daily_topics',
13106            'user_membership' => $userData->getMembershipTypeIndex(),
13107            'allow_language' => Configure::read('campaign_config.daily_topics.allowed_languages'),
13108            'user_language' => $userData->native_language2,
13109            'allow_currency' => Configure::read('campaign_config.daily_topics.allowed_currencies'),
13110            'user_currency' => $userData->currency_code,
13111        );
13112        if(!$counseling_flg && $campaignSetting->campaignChecker($dailytopicsCamp)){
13113            $dailytopicsCampSettingId = Configure::read('campaign_config.daily_topics.modal_settings.after_lesson');
13114            $displayModalAfterLesson = (!in_array($dailytopicsCampSettingId, $dontShowCampaignModals)) ? true : false;
13115            if($displayModalAfterLesson){
13116                $modalCampaignType = 'campaign_dailytopics_afterlesson';
13117                $campaignTerm = true;
13118            }
13119        }
13120
13121        $response['campaign_name'] = $modalCampaignType;
13122        $response['campaignPageRecord'] = $campaignPageRecord;
13123        $response['campaignTerm'] = $campaignTerm;
13124
13125        return $response;
13126    }
13127
13128
13129    //Retrieves the active campaign stamp data for the authenticated user in Native Camp. It checks various campaigns and sets the campaign data for the view.
13130    public function getActiveCampaignStampData($params = []) {
13131
13132        $usrObj = new UserTable($this->sharedUserData['User']);
13133        $cst_ = ClassRegistry::init('CampaignSettingTable');
13134
13135        // - NJ-31307 Callan unlimited campaign
13136        $camp_callan_unlimited = array(
13137            'campaign' => 'callan_unlimited',
13138            'user_membership' => $usrObj->getMembershipTypeIndex()
13139        );
13140        if($cst_->campaignChecker($camp_callan_unlimited)){
13141            $campaignStamp = $cst_->callanUnlimitedCampaign(array(
13142                'trigger' => 1,
13143                'user_id' => $usrObj->id
13144            ));
13145            $camp_callan_unlimited_ID = Configure::read('campaign_config.callan_unlimited.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
13146            $this->set('campaignStamp', $campaignStamp);
13147            $this->set('callanUnlimitedSettingID', $camp_callan_unlimited_ID);
13148            $this->set('showCallanUnlimitedAfterLessonModal', true);
13149        }
13150
13151        // - NJ-32989 : New Year Lottery Campaign
13152        $camp_new_year_lottery = array(
13153            'campaign' => 'new_year_lottery',
13154            'user_membership' => $usrObj->getMembershipTypeIndex(),
13155            'user_language' => $usrObj->native_language2,
13156            'allow_language' => Configure::read('campaign_config.new_year_lottery.allow_languages'),
13157            'user_currency' => $usrObj->currency_code,
13158            'other_validation' => true,
13159        );
13160        if($cst_->campaignChecker($camp_new_year_lottery)){
13161            $campaignLotteryTicket = $cst_->newYearLotteryCamp(array(
13162                'trigger' => 1,
13163                'user_id' => $usrObj->id
13164            ));
13165            $camp_new_year_lottery_ID = Configure::read('campaign_config.new_year_lottery.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
13166            $this->set('campaignLotteryTicket', $campaignLotteryTicket);
13167            $this->set('newYearLotterySettingID', $camp_new_year_lottery_ID[0]);
13168            $this->set('showNewYearLotteryAfterLessonModal', true);
13169        }
13170
13171        // - NJ-32989 Around the world campaign
13172        $camp_around_the_world = array(
13173            'campaign' => 'around_the_world',
13174            'user_membership' => $usrObj->getMembershipTypeIndex(),
13175            'user_currency' => $usrObj->currency_code,
13176            'allow_currency' => Configure::read('campaign_config.around_the_world.allow_currencies'),
13177            'user_language' => $usrObj->native_language2,
13178            'allow_language' => Configure::read('campaign_config.around_the_world.allow_languages'),
13179
13180        );
13181        if($cst_->campaignChecker($camp_around_the_world)){
13182            $stampData = ClassRegistry::init('CampaignSettingTable')->aroundTheWorldCamp(['user_id' => $usrObj->id, 'trigger' => 1]);
13183            $camp_around_the_world_ID = Configure::read('campaign_config.around_the_world.modal_settings.after_lesson');
13184            $this->set('aroundTheWorldSettingID', $camp_around_the_world_ID);
13185            $this->set('showAroundTheWorldAfterLessonModal', true);
13186            $this->set('total_stamp_count', $stampData['total_count'] ?? 0 );
13187            $this->set('stamp_html', $stampData['stamp_html'] ?? '' );
13188        }
13189
13190        // - NJ-36818 : What are you doing now? Native Camp! Campaign
13191        $camp_spare_time = array(
13192            'campaign' => 'spare_time_march',
13193            'user_membership' => $usrObj->getMembershipTypeIndex(),
13194            'user_language' => $usrObj->native_language2,
13195            'allow_language' => Configure::read('campaign_config.spare_time_march.allow_languages'),
13196        );
13197        if($cst_->campaignChecker($camp_spare_time)){
13198            $campaignStamp = $cst_->spareTimeCampaign(array(
13199                'trigger' => 1,
13200                'user_id' => $usrObj->id
13201            ));
13202            $camp_spare_time_ID = Configure::read('campaign_config.spare_time_march.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
13203            $this->set('spareTimeCampaignStamp', $campaignStamp);
13204            $this->set('spareTimeSettingID', $camp_spare_time_ID);
13205            $this->set('showSpareTimeAfterLessonModal', true);
13206        }
13207
13208        // 1.5 Million - Thank You Campaign
13209        $camp_opfm = array(
13210            'campaign' => 'OPFM_campaign',
13211            'user_membership' => $usrObj->getMembershipTypeIndex(),
13212            'user_language' => $usrObj->native_language2,
13213            'allow_language' => Configure::read('campaign_config.OPFM_campaign.allow_languages'),
13214        );
13215        if($cst_->campaignChecker($camp_opfm)){
13216            $campaignStamp = $cst_->opfmCampaign(array(
13217                'trigger' => 1,
13218                'user_id' => $usrObj->id
13219            ));
13220            $camp_opfm_ID = Configure::read('campaign_config.OPFM_campaign.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
13221            $this->set('opfmCampaignStamp', $campaignStamp);
13222            $this->set('opfmSettingID', $camp_opfm_ID);
13223            $this->set('showOpfmAfterLessonModal', true);
13224        }
13225
13226        // - NJ-42488 : kakaku_01 campaign
13227        $camp_kakaku01 = array(
13228            'campaign' => 'kakaku_01',
13229            'user_membership' => $usrObj->getMembershipTypeIndex()
13230        );
13231        if($cst_->campaignChecker($camp_kakaku01)){
13232            $kakakuCampaignStamp = ClassRegistry::init('CampaignSettingTable')->kakaku01_camp(array(
13233                'trigger' => 1,
13234                'user_id' => ($this->Auth->loggedIn()) ? $usrObj->id : null,
13235            ));
13236            $camp_kakaku_01_IDs = Configure::read('campaign_config.kakaku_01.modal_settings.after_lesson');
13237            if( $usrObj->native_language2 == Configure::read('default.user_language')){
13238                $this->set('kakakuCampaignStamp', $kakakuCampaignStamp);
13239                $this->set('kakaku01SettingID', $camp_kakaku_01_IDs[0]);
13240                $this->set('showKakaku01AfterLessonModal', true);
13241            } else {
13242                $this->set('kakakuCampaignStamp', $kakakuCampaignStamp);
13243                $this->set('kakaku01SettingID', $camp_kakaku_01_IDs[1]);
13244                $this->set('showKakaku01DailyNewsAfterLessonModal', true);
13245            }
13246        }
13247
13248        // - NJ-42488 : kakaku_01 campaign
13249        $camp_ai_speaking_sept = array(
13250            'campaign' => 'ai_speaking_sept',
13251            'user_membership' => $usrObj->getMembershipTypeIndex(),
13252            'user_language' => $usrObj->native_language2,
13253            'allow_language' => Configure::read('campaign_config.ai_speaking_sept.allow_languages')
13254        );
13255        if($cst_->campaignChecker($camp_ai_speaking_sept)){
13256            $aiSpeakingSeptCampaignStamp = ClassRegistry::init('CampaignSettingTable')->ai_speaking_camp(array(
13257                'trigger' => 1,
13258                'user_id' => ($this->Auth->loggedIn()) ? $usrObj->id : null,
13259            ));
13260            $camp_ai_speaking_sept_IDs = Configure::read('campaign_config.ai_speaking_sept.modal_settings.after_lesson');
13261            $this->set('aiSpeakingSeptCampaignStamp', $aiSpeakingSeptCampaignStamp);
13262            $this->set('aiSpeakingSeptSettingID', $camp_ai_speaking_sept_IDs[0]);
13263            $this->set('showAISpeakingSeptAfterLessonModal', true);
13264        }
13265
13266        //NJ-50048 Lesson coin gift campaign
13267        $lessonCoinGiftCamp = array(
13268            'campaign' => 'taking_lesson_and_continue_plan',
13269            'user_membership' => $usrObj->getMembershipTypeIndex(),
13270            'allow_language' => Configure::read('campaign_config.taking_lesson_and_continue_plan.allowed_languages'),
13271            'user_language' => $usrObj->native_language2,
13272        );
13273        if($cst_->campaignChecker($lessonCoinGiftCamp)){
13274            $campModalSettingIDs = Configure::read('campaign_config.taking_lesson_and_continue_plan.modal_settings');
13275            $lessonCoinGiftCampSettingID = $campModalSettingIDs['after_lesson'];
13276            $dataStamp = $cst_->takingLessonAndContinuePlan(array('user_id' => $usrObj->id, 'type' => 1, 'device' => 1));
13277            $this->set('dataStamp', $dataStamp);
13278            $this->set('lessonCoinGiftCampSettingID', $lessonCoinGiftCampSettingID);
13279            $this->set('showLessonCoinGiftCampAfterLessonModal', true);
13280        }
13281
13282        //NJ-55569 2025 New Year Campaign
13283        $newYearCamp = array(
13284            'campaign' => 'newyear_2025',
13285            'user_membership' => $usrObj->getMembershipTypeIndex(),
13286            'allow_language' => Configure::read('campaign_config.newyear_2025.allowed_languages'),
13287            'user_language' => $usrObj->native_language2,
13288            'allow_currency' => Configure::read('campaign_config.newyear_2025.allowed_currencies'),
13289            'user_currency' => $usrObj->currency_code,
13290        );
13291        if($cst_->campaignChecker($newYearCamp)){
13292            $campModalSettingIDs = Configure::read('campaign_config.newyear_2025.modal_settings');
13293            $newYearCampSettingID = $campModalSettingIDs['after_lesson'];
13294            $newyear2025_stamp = $cst_->newyear2025_camp(array('user_id' => $usrObj->id, 'trigger' => 1));
13295            $this->set('newyear2025_stamp', $newyear2025_stamp);
13296
13297            if( $usrObj->native_language2 == Configure::read('default.user_language')){
13298                $this->set('showNewYearCampAfterLessonModal', true);
13299                $this->set('newYearCampSettingID', $newYearCampSettingID[0]);
13300            } else {
13301                $this->set('showNewYearDailyNewsCampAfterLessonModal', true);
13302                $this->set('newYearCampSettingID', $newYearCampSettingID[1]);
13303            }
13304        }
13305
13306        //NJ-59889 3 Million Campaign
13307        $threeMillionCamp = array(
13308            'campaign' => '3_million',
13309            'user_membership' => $usrObj->getMembershipTypeIndex(),
13310            'allow_language' => Configure::read('campaign_config.3_million.allowed_languages'),
13311            'user_language' => $usrObj->native_language2,
13312            'allow_currency' => Configure::read('campaign_config.3_million.allowed_currencies'),
13313            'user_currency' => $usrObj->currency_code,
13314        );
13315        if($cst_->campaignChecker($threeMillionCamp)){
13316            $threeMillionCampSettingId = Configure::read('campaign_config.3_million.modal_settings.after_lesson');
13317            $campaignStamp = $cst_->threeMillionCamp([
13318                'trigger' => 1,
13319                'user_id' => $usrObj->id,
13320                'lang' => $this->localizeDir
13321            ]);
13322            $this->set( 'threeMillionCampaignStamp', $campaignStamp );
13323            $this->set('showthreeMillionCampAfterLessonModal', true);
13324            $this->set('threeMillionCampSettingId', $threeMillionCampSettingId);
13325        }
13326
13327        // - NJ-65066 【Campaign】Daily Topics
13328        $dailytopicsCamp = array(
13329            'campaign' => 'daily_topics',
13330            'user_membership' => $usrObj->getMembershipTypeIndex(),
13331            'allow_language' => Configure::read('campaign_config.daily_topics.allowed_languages'),
13332            'user_language' => $usrObj->native_language2,
13333            'allow_currency' => Configure::read('campaign_config.daily_topics.allowed_currencies'),
13334            'user_currency' => $usrObj->currency_code,
13335        );
13336        if($cst_->campaignChecker($dailytopicsCamp)){
13337            $dailytopicsCampSettingId = Configure::read('campaign_config.daily_topics.modal_settings.after_lesson');
13338            $campaignStamp = $cst_->dailyTopics([
13339                'trigger' => 1,
13340                'user_id' => $usrObj->id,
13341                'lang' => $this->localizeDir
13342            ]);
13343            $this->set( 'dailytopicsCampaignStamp', $campaignStamp );
13344            $this->set('showdailytopicsCampAfterLessonModal', true);
13345            $this->set('dailytopicsCampSettingId', $dailytopicsCampSettingId);
13346        }
13347        
13348        $this->set('userToken', $this->Auth->user('api_token'));
13349    }
13350
13351
13352    //Determines whether to show the campaign modal based on the current date and the provided start and end dates.
13353    public function showCampaignModal($startDate = null, $endDate = null){
13354        if(!empty($startDate) && !empty($endDate)){
13355            $current_date = strtotime('now');
13356            $showCampaignModal = $current_date >= strtotime($startDate) && $current_date <= strtotime($endDate) ? true : false;
13357
13358            return $showCampaignModal;
13359        }
13360
13361        return false;
13362    }
13363
13364    /**
13365     * @api {post} /user/waiting/generateTextbookTeacherRecommendAjax generateTextbookTeacherRecommendAjax()
13366     * @apiName generateTextbookTeacherRecommendAjax
13367     * @apiGroup Waiting
13368     * @apiDescription Generates a list of recommended teachers for a specific textbook in Native Camp. It retrieves the teacher recommendations based on the user's last lesson and textbook data.
13369     *
13370     * @apiBody {String} category_id The ID of the textbook category.
13371     * @apiBody {String} connect_id The ID of the textbook connect.
13372     * @apiBody {String} teacher_id The ID of the teacher.
13373     * 
13374     * @apiSuccess {Number} result Indicates whether the operation was successful.
13375     * @apiSuccess {String} html The HTML content for the recommended teachers modal.
13376     *
13377     * @apiSuccessExample {json} Success-Response:
13378     *     {
13379     *         "result": 1,
13380     *         "html": "<div>Recommended Teachers</div>"
13381     *     }
13382     *
13383     * @apiError {Number} result Indicates whether the operation was successful.
13384     * @apiError {String} html The HTML content for the recommended teachers modal.
13385     *
13386     * @apiErrorExample {json} Error-Response:
13387     *     {
13388     *         "result": 0,
13389     *         "html": ""
13390     *     }
13391     * 
13392     * @apiSampleRequest off
13393     */
13394    public function generateTextbookTeacherRecommendAjax() {
13395        $this->autoRender = false;
13396        $this->layout = false;
13397        $resultSuccess = 0;
13398        $resultHTML = '';
13399        $isSubmittedFiveStar = 0;
13400        if ($this->request->is('ajax')) {
13401
13402            $curDate = date('Y-m-d');
13403            $userId = $this->Auth->user('id') ? $this->Auth->user('id') : null;
13404            $txtTeacherRecommendlimit = 3; // modal limit
13405            $userData = isset($this->sharedUserData['User']) && $this->sharedUserData['User'] ? $this->sharedUserData['User'] : null;
13406            $endDate = date('Y-m-d',strtotime('-1 day' ,strtotime($curDate)));
13407            $beginDate = date('Y-m-d',strtotime('-1 month' ,strtotime($curDate)));
13408            $categoryId = isset($this->request->data['category_id']) ? $this->request->data['category_id'] : null;
13409            $connectId = isset($this->request->data['connect_id']) ? $this->request->data['connect_id'] : null;
13410            $teacherId = isset($this->request->data['teacher_id']) ? $this->request->data['teacher_id'] : null;
13411            $chatHash = isset($this->request->data['chat_hash']) ? $this->request->data['chat_hash'] : null;
13412
13413            if( $userId ) {
13414
13415
13416                // - NJ-8416: check for last lesson type
13417                $lastLessonType = ClassRegistry::init('LessonOnair')->getLastLessonType($userId);
13418                $this->log('[NJ-8416 lastLessonType lessonFinish] -> ' . json_encode($lastLessonType), 'debug');
13419                $lastBookUsedData = $this->UsersTextbookInfo->getCurrentTextbookAndBadgeData( array( 
13420                        'user_id' => $userId,
13421                        'connect_id' => $connectId,
13422                        'limit' => 3, // modal
13423                        'last_lesson_type' => $lastLessonType
13424                    ) 
13425                );
13426
13427                $textbookCategoryId = $lastBookUsedData['category_id'];
13428                $textbookBadge = $lastBookUsedData['textbook_badge'];
13429                $this->log('[NJ-8416 textbookCategoryId lessonFinish] -> ' . json_encode($textbookCategoryId), 'debug');
13430                $paramsArr = array(
13431                    'user_id' => $userId,
13432                    'begin_date' => $beginDate,
13433                    'end_date' => $endDate,
13434                    'textbook_category' => $textbookCategoryId,
13435                    'textbook_badge' => $textbookBadge,
13436                    'limit' => $txtTeacherRecommendlimit,
13437                    'user_data' => $userData,
13438                    'exclude_teacher_id' => $teacherId
13439                );
13440
13441                $teacherTextbookStatData = $this->TeacherTextbookStat->fetchTextbookTeacherRatingData($paramsArr);
13442                if( $teacherTextbookStatData ) {
13443                    $dataList = $this->arrangeTeacherRecommendList( array( 
13444                            'user_id' => $userId,
13445                            'data' => $teacherTextbookStatData,
13446                            'category_id' => $textbookCategoryId,
13447                            'user_data' => $userData
13448                        )
13449                    );
13450
13451                    $this->set('textbookTeacherData', $dataList);
13452                    $view = new View($this, false);
13453                    $resultHTML = $view->element( 'lesson_finish_textbook_teacher_list_modal', array(
13454                            'textbookTeacherData' => isset($dataList) && $dataList ? $dataList : array()
13455                        )
13456                    );
13457                    $resultSuccess = 1;
13458                }
13459
13460                //- NJ-61019: get rating from mecached
13461                if($chatHash && $chatHash != 'hash') {
13462                    if (!class_exists('myMemcached')) {
13463                        App::uses('myMemcached', 'Lib');
13464                    }
13465                    $memcached = new myMemcached();
13466                    $rate = $memcached->get("rating_".$chatHash);
13467
13468                    if(isset($rate) && $rate == 5) {
13469                        $isSubmittedFiveStar = 1;
13470                    }
13471                }
13472            }
13473
13474        }
13475        return json_encode(array(
13476            'result' => $resultSuccess,
13477            'html' => $resultHTML,
13478            'isSubmittedFiveStar' => $isSubmittedFiveStar
13479        ));
13480    }
13481
13482    /**
13483    * Ajax Request : fetch user's appreciation options data for modal display
13484    */
13485    //not used function
13486    public function setUpAppreciationSelectionModalElementAjax() {
13487        $this->autoRender = false;
13488        $this->layout = false;
13489        $result = array();
13490        if ($this->request->is('ajax')) {
13491            $chatHash = isset($this->request->data['chat_hash']) ? $this->request->data['chat_hash'] : null;
13492            if($chatHash){
13493                $fetchParam = array( 'chat_hash'  => $chatHash );
13494                $fetchedData = $this->setUpAppreciationSelectionModalElement($fetchParam);
13495                if( isset( $fetchedData['html_element'] ) && $fetchedData['html_element'] ){
13496                    $result['html_element'] = $fetchedData['html_element'];
13497                }
13498            }
13499        }
13500        return json_encode(array(
13501            'result' => $result
13502        ));
13503    }
13504
13505    /**
13506    * Ajax Request : Send teacher's appreciation
13507    */
13508    //not used function
13509    public function sendTeacherAppreciationAjax() {
13510        $this->autoRender = false;
13511        $this->layout = false;
13512        $result = array( 'result' => 0 );
13513        $teacherAppreciationMessage = "";
13514        $teacherAppreciationAmount = 0;
13515        $hasTips = 1;
13516        $hasMessage = 1;
13517        $noMessageText = '';
13518        $noTipsText = '';
13519
13520        if ($this->request->is('ajax')) {
13521            $appreciationId = isset($this->request->data['appreciation_ration_input']) ? $this->request->data['appreciation_ration_input'] : null;
13522            $message = isset($this->request->data['user_comment_text']) ? trim($this->request->data['user_comment_text']) : null;
13523            $chatHash = isset($this->request->data['chat_hash_input']) ? $this->request->data['chat_hash_input'] : null;
13524            $actionMode = isset($this->request->data['action_mode']) ? $this->request->data['action_mode'] : 0;
13525            
13526            // - initialize api tunnel
13527            myTools::initializeApiTunnel(array('AppreciationController'));    
13528            $params = array(
13529                "users_api_token" => $this->Auth->user('api_token'),
13530                'chat_hash' => $chatHash,
13531                'appreciation_id'  => $appreciationId,
13532                'message' => $message,
13533                'nc_terminal_type' => Configure::read('nc_terminal_type.pc')
13534
13535            );
13536            $api = new AppreciationController();
13537            $api->params = $params;
13538            
13539            // - send teacher appreciation
13540            $sendData = $api->send();
13541
13542            // - Detect prohibited words in teacher appreciation messages sent after class.
13543            $this->ProhibitedWord->detectProhibitedWordOnStudentAppreciation([
13544                'chat_hash' => $chatHash,
13545                'message' => $message,
13546            ]);
13547            
13548            if ( isset ($sendData['result'] ) && $sendData['result'] ) {
13549                // set default res
13550                $result = array( 'result' => 1 );
13551
13552                // set return appreciation item
13553                $appreciationDetails = $sendData['appreciation_item'];
13554
13555            } else {
13556                if( isset ($sendData['error'] ) && $sendData['error'] ){
13557                    $result['error']['id'] = 'sending_failed';
13558                    $result['error']['message'] = json_encode($sendData['error']);
13559                }
13560            }
13561
13562            // set appreciation details student message
13563            if(empty($appreciationDetails['student_message'])){
13564                $appreciationDetails['student_message'] = __d('modal','このお礼にメッセージはありません。');
13565                $appreciationDetails['student_message_flg'] = false;
13566            }else{
13567                $appreciationDetails['student_message_flg'] = true;
13568            }
13569
13570            if ( isset ($sendData['result'] ) && $sendData['result'] ) {
13571                $teacherAppreciationMessage = $appreciationDetails['message'];
13572                $teacherAppreciationAmount = $appreciationDetails['amount'];
13573
13574                if(empty($appreciationId)) {
13575                    // no apprecation tips form
13576                    $hasTips = 0;
13577                    if($appreciationId != 0)  {
13578                        $hasTips = 0;
13579                    }
13580                    $noTipsText = __d('modal','チップはありません');
13581                }
13582
13583                if (empty($message)) {
13584                    // no appreciation message form
13585                    $hasMessage = 0;
13586                    $noMessageText = __d('modal','メッセージはありません');
13587                }
13588
13589                $result = array( 'result' => 1 );
13590
13591                if ($actionMode == 1) {
13592                    $hasTips = 1;
13593                    $hasMessage = 1;
13594                }
13595
13596            } else {
13597                if( isset ($sendData['error'] ) && $sendData['error'] ){
13598                    $result['error']['id'] = 'sending_failed';
13599                    $result['error']['message'] = json_encode($sendData['error']);
13600                    if(isset($sendData['error']['error_code'])) {
13601                        $result['error']['error_code'] = json_encode($sendData['error']['error_code']);
13602                    }
13603                }
13604            }    
13605
13606        }
13607        return json_encode(array(
13608            'output' => $result,
13609            'appreciation_message' => $teacherAppreciationMessage,
13610            'appreciation_amount' => $teacherAppreciationAmount,
13611            'has_tips' => $hasTips,
13612            'has_message' => $hasMessage,
13613            'appreciation_details' => $appreciationDetails,
13614            'no_message_text' => $noMessageText,
13615            'no_tips_text' => $noTipsText
13616        ));
13617    }
13618
13619
13620    /**
13621    * ajax set after lesson evaluate system problem
13622    */
13623    //not used function
13624    public function ajaxUpdateSystemTrouble() {
13625        $this->autoRender = false;
13626        $this->layout = false;
13627        $troubleResponse = false;
13628        if ($this->request->is('ajax')) {
13629            $chatHash = isset($this->request->data['chat_hash']) ? $this->request->data['chat_hash'] : '';
13630            $status = isset($this->request->data['value']) ? $this->request->data['value'] : 0;
13631            $lesson = $this->LessonOnairsLog->findByChatHash($chatHash, array('LessonOnairsLog.id'),null, -1);
13632            if (isset($lesson) && $lesson) {
13633                if (isset($lesson['LessonOnairsLog']['id']) && $lesson['LessonOnairsLog']['id']) {
13634                    if($this->LessonOnairsLog->read(null, $lesson['LessonOnairsLog']['id'])){
13635                        $this->LessonOnairsLog->saveField('lesson_system_trouble', $status);
13636                    }
13637                    $troubleResponse = true;
13638                }
13639            } 
13640        }
13641        return json_encode(array(
13642            'result' => $troubleResponse
13643        ));
13644    }
13645
13646    /**
13647     * @api {post} /user/waiting/reportProblem reportProblem()
13648     * @apiName reportProblem
13649     * @apiGroup Waiting
13650     * @apiDescription Reports a problem during a lesson in Native Camp. It updates the lesson status and sends a notification to Slack.
13651     *
13652     * @apiBody {String} problem The description of the problem.
13653     * @apiBody {String} chatHash The chat hash of the lesson.
13654     * @apiBody {String} [member_type] The type of the member (viewer or student).
13655     * 
13656     * @apiSuccess {Boolean} success Indicates whether the operation was successful.
13657     *
13658     * @apiSuccessExample {json} Success-Response:
13659     *     {
13660     *         "success": true
13661     *     }
13662     *
13663     * @apiError {Boolean} success Indicates whether the operation was successful.
13664     *
13665     * @apiErrorExample {json} Error-Response:
13666     *     {
13667     *         "success": false
13668     *     }
13669     * 
13670     * @apiSampleRequest off
13671     */
13672    public function reportProblem() {
13673        $this->autoRender = false;
13674        $this->layout = false;
13675
13676        if ($this->Auth->loggedIn() && isset($this->request->data['problem']) && isset($this->request->data['chatHash'])) {
13677            //get data
13678            $problem = $this->request->data['problem'];
13679            $chatHash = $this->request->data['chatHash'];
13680            $userId = $this->Auth->user('id');
13681            $memberType = isset($this->request->data['member_type']) ? $this->request->data['member_type'] : 'student';
13682
13683            if ($memberType == 'viewer') {
13684                //-live_system_trouble
13685                $res = $this->LessonOnairsViewer->updateAll(
13686                    array(
13687                        'LessonOnairsViewer.live_system_trouble' => 1
13688                    ),
13689                    array(
13690                        'LessonOnairsViewer.user_id' => $userId,
13691                        'LessonOnairsViewer.chat_hash' => $chatHash
13692                    )
13693                );
13694                return json_encode(array('success' => ($res?true:false)));
13695            }
13696
13697            $lessonData = LessonOnairTable::findLessonData(array(
13698                'fields' => array(
13699                    'id',
13700                    'teacher_id',
13701                    'user_id',
13702                    'chat_hash',
13703                    'lesson_system_trouble',
13704                    'user_agent'
13705                ),
13706                'conditions' => array(
13707                    'chat_hash' => $chatHash,
13708                    'user_id' => $userId
13709                )
13710            ));
13711
13712            //if no lesson data found
13713            if (!$lessonData) {
13714                return json_encode(array('success' => false));
13715            } elseif ($lessonData['data']['lesson_system_trouble'] == 0) {
13716                //update trouble
13717                $model = ClassRegistry::init($lessonData['model']);
13718                if ($model->read(null, $lessonData['data']['id'])) {
13719                    $model->set('lesson_system_trouble', 1);
13720                    $model->save();
13721                }
13722            }            
13723
13724            //fetch data
13725            $finalData = $lessonData['data'];
13726            $finalData['user_name'] = $this->Auth->user('nickname');
13727
13728            //query teacher name
13729            $teacherData = $this->Teacher->find('first', array(
13730                'fields' => 'name',
13731                'conditions' => array('Teacher.id' => $finalData['teacher_id']),
13732                'recursive' => -1
13733            ));
13734
13735            //set teacher name
13736            $finalData['teacher_name'] = isset($teacherData['Teacher']['name']) ? $teacherData['Teacher']['name'] : ''; 
13737
13738            //fetch problem data
13739            $problemData = $this->LessonOnairsLog->countProblematicLesson(array(
13740                'userId' => $userId,
13741                'teacherId' => $finalData['teacher_id'],
13742                'lessonData' => $lessonData['data']
13743            ));
13744
13745            // send to slack
13746            $slack = new mySlack();
13747            // set the channel, change to #nc-monitoring
13748            $slack->channel  = myTools::checkChannel("#nc-voice-trouble", "#nc-voice-trouble-dev");
13749            //type
13750            $slack->text = "```種別:通信トラブル(PC)\n";
13751            // set os and problem count
13752            $slack->text .= "本日:{$problemData['totalProblemCount']}件目({$problemData['userAgentStr']})\n";
13753            // set lecturer id and number of lesson
13754            $slack->text .= "講師ID:{$finalData['teacher_id']} ({$finalData['teacher_name']})(本日{$problemData['teacherCount']}回目)\n";
13755            // set member id and number of lesson
13756            $slack->text .= "会員ID:{$userId} ({$finalData['user_name']})(本日{$problemData['userCount']}回目)\n";
13757            // set contents
13758            $slack->text .= "内容:{$problem}\n";
13759            // set chat hash
13760            $slack->text .= "chathash: https://{$_SERVER['HTTP_HOST']}/admin/lesson-history?chat_hash={$chatHash}" . '```';
13761            // set slack user name
13762            $slack->username = "NativeCamp";
13763
13764            // send slack
13765            $resp = $slack->sendSlack(); //returns http code
13766            if ($resp) {
13767                return json_encode(array('success' => true));
13768            }
13769        }
13770        return json_encode(array('success' => false));
13771    }
13772
13773    /**
13774     * @api {post} /user/waiting/getApppreciationModal getApppreciationModal()
13775     * @apiName getApppreciationModal
13776     * @apiGroup Waiting
13777     * @apiDescription Retrieves the appreciation modal data for a specific lesson in Native Camp. It checks the appreciation status and returns the appreciation data.
13778     *
13779     * @apiBody {String} chat_hash The chat hash of the lesson.
13780     * @apiBody {String} member_type The type of the member (viewer or student).
13781     * 
13782     * @apiSuccess {Boolean} error Indicates whether there was an error.
13783     * @apiSuccess {String} [error_msg] The error message (if any).
13784     * @apiSuccess {String} [appreciation_data] The HTML element for the appreciation data.
13785     * @apiSuccess {Boolean} [appreciation_done] Indicates whether the appreciation is done.
13786     *
13787     * @apiSuccessExample {json} Success-Response:
13788     *     {
13789     *         "error": false,
13790     *         "appreciation_data": "<div>Appreciation Data</div>",
13791     *         "appreciation_done": true
13792     *     }
13793     *
13794     * @apiError {Boolean} error Indicates whether there was an error.
13795     * @apiError {String} error_msg The error message.
13796     *
13797     * @apiErrorExample {json} Error-Response:
13798     *     {
13799     *         "error": true,
13800     *         "error_msg": "An error occurred."
13801     *     }
13802     * 
13803     * @apiSampleRequest off
13804     */
13805    public function getApppreciationModal() {
13806        $this->autoRender = false;
13807        $this->layout = false;
13808
13809        if ($this->request->is('ajax')) {
13810            $response = array();
13811            $data = $this->request->data;
13812
13813            try  {
13814                if (!empty($data['member_type']) && $data['member_type'] !== 'viewer') {
13815                    // Check appreciation data
13816                    $appreciationElementData = $this->setUpAppreciationSelectionModalElement( array( 'chat_hash' => $data['chat_hash'] ) );
13817                    if(!empty($appreciationElementData['html_element'])){
13818                        $response['appreciation_data'] = $appreciationElementData['html_element'];
13819                    }
13820                    $elapsed5mins = false;
13821                    // 5mins elapsed only
13822                    $lessonExists = $this->LessonOnairsLog->isLessonEnded($data['chat_hash']);
13823                    if ($lessonExists) {
13824                        $this->LessonOnairsLog->openDBReplica();
13825                        $created = $this->LessonOnairsLog->find('first', [
13826                            'fields' => ['created'],
13827                            'conditions' => ['chat_hash' => $data['chat_hash']]
13828                        ]);
13829                        $this->LessonOnairsLog->closeDBReplica();
13830                        if (!empty($created)){
13831                            $created = $created['LessonOnairsLog']['created'];
13832                            $now = date('Y-m-d H:i:s');
13833                            $elapsed5mins = ( strtotime($now) - strtotime($created)) > 300;
13834                        }
13835                    }
13836                    $response['has_elapsed'] = $elapsed5mins;
13837                    $response['appreciation_done'] = $this->getAppreciationStatus($data['chat_hash']);
13838                    $response['error'] = false;
13839                }
13840                return json_encode($response);
13841                
13842            } catch (Exception $e) {
13843                $response['error'] = true;
13844                $response['error_msg'] = $e->getMessage();
13845
13846                 // - add logger
13847                 $mySlack = new mySlack();
13848                 $mySlack->channel = myTools::checkChannel("#fdci-irregular-monitoring");
13849                 $mySlack->token = "xoxb-392902820692-6499139810404-RHHGc6Z5ZB9o2KkiGhzTTtlQ";
13850                 $mySlack->username = "GetAppreciationModalFailed";
13851                 $mySlack->text = "```";
13852                 $mySlack->text .= "Message : ". $e->getMessage() ."\n";
13853                 $mySlack->text .= "Chat-hash: ". $data['chat_hash'] ."\n";
13854                 $mySlack->text .= "Student ID: ". $this->Auth->user('id') ."\n";
13855                 $mySlack->text .= "UA: ". $_SERVER['HTTP_USER_AGENT'] ."\n";
13856                 $mySlack->text .= "referrer: ". $_SERVER['HTTP_REFERER'] ."\n";
13857                 $mySlack->text .= "```";
13858                 // - send slack message
13859                 $mySlack->sendSlack();
13860                return json_encode($response);
13861            }
13862        }
13863    }
13864
13865    private function getAppreciationStatus($chatHash) {
13866        $doneAppreciation = false;
13867        $appreFields = array(
13868            'TeacherCoinBox.has_tips',
13869            'TeacherCoinBox.done_flg'
13870        );
13871        $checkCoinBoxData = $this->TeacherCoinBox->getData(array('chat_hash' => $chatHash), $appreFields);
13872        if(
13873            $checkCoinBoxData && 
13874            (isset($checkCoinBoxData['TeacherCoinBox']['has_tips']) && $checkCoinBoxData['TeacherCoinBox']['has_tips']) ||
13875            (isset($checkCoinBoxData['TeacherCoinBox']['done_flg']) && $checkCoinBoxData['TeacherCoinBox']['done_flg'])
13876        ) {
13877            $doneAppreciation = true;
13878        }
13879
13880        return $doneAppreciation;
13881    }
13882
13883    /**
13884     * @api {post} /user/waiting/getEvaluationDetail getEvaluationDetail()
13885     * @apiName getEvaluationDetail
13886     * @apiGroup Waiting
13887     * @apiDescription Retrieves the evaluation detail for a specific lesson in Native Camp. It checks if the user has already submitted an evaluation for the lesson.
13888     *
13889     * @apiBody {String} chat_hash The chat hash of the lesson.
13890     * @apiBody {String} [member_type] The type of the member (viewer or student).
13891     * 
13892     * @apiSuccess {Boolean} status Indicates whether the evaluation has been submitted.
13893     *
13894     * @apiSuccessExample {json} Success-Response:
13895     *     {
13896     *         "status": true
13897     *     }
13898     *
13899     * @apiError {String} error Message indicating the error.
13900     *
13901     * @apiErrorExample {json} Error-Response:
13902     *     {
13903     *         "error": "Invalid request."
13904     *     }
13905     * 
13906     * @apiSampleRequest off
13907     */
13908    public function getEvaluationDetail() {
13909        $this->autoRender = false;
13910        $this->layout = false;
13911        $doneReview['status'] = false;
13912        if ($this->request->is('ajax')) {
13913            $chatHash = isset($this->request->data['chat_hash']) ? $this->request->data['chat_hash'] : '';
13914            //-check if viewer
13915            if (isset($this->request->data['member_type']) && $this->request->data['member_type'] == 'viewer') {
13916                $eval = $this->ViewersClassEvaluation->find('first', [
13917                    'conditions' => [
13918                        'ViewersClassEvaluation.user_id' => $this->Auth->user('id'),
13919                        'ViewersClassEvaluation.chat_hash' => $chatHash
13920                    ]
13921                ]);
13922                $doneReview['status'] = !empty($eval);        
13923            } else {
13924                if ($this->UsersClassEvaluation->findByChatHash($chatHash)) {
13925                    $doneReview['status'] = true;
13926                }
13927            }
13928        }
13929        return json_encode($doneReview);
13930    }
13931    /**
13932     * @api {post} /user/waiting/resetLessonReviewModal resetLessonReviewModal()
13933     * @apiName resetLessonReviewModal
13934     * @apiGroup Waiting
13935     * @apiDescription Resets the lesson review modal status for a specific lesson and user in Native Camp. It deletes the modal status from the cache.
13936     *
13937     * @apiBody {String} chatHash The chat hash of the lesson.
13938     * @apiBody {String} userId The ID of the user.
13939     * 
13940     * @apiSuccess {Boolean} res Indicates whether the operation was successful.
13941     *
13942     * @apiSuccessExample {json} Success-Response:
13943     *     {
13944     *         "res": true
13945     *     }
13946     *
13947     * @apiError {String} error Message indicating the error.
13948     *
13949     * @apiErrorExample {json} Error-Response:
13950     *     {
13951     *         "error": "Invalid request."
13952     *     }
13953     * 
13954     * @apiSampleRequest off
13955     */
13956    public function resetLessonReviewModal() {
13957        $this->autoRender = false;
13958        $this->layout = false;
13959        if ($this->request->is('ajax')) {
13960            $chatHash = $this->request->data('chatHash');
13961            $userId = $this->request->data('userId');
13962            $memcached = new myMemcached();
13963            $modalStatus = $memcached->get('lesson-review-modal-'. $chatHash .'-'. $userId);
13964            if ($modalStatus !== false) {
13965                $memcached->delete('lesson-review-modal-' . $chatHash .'-'. $userId);
13966            }
13967        }
13968        echo json_encode(array('res' => true));
13969    }
13970
13971    /**
13972     * @api {post} /user/waiting/finishOnlineLesson finishOnlineLesson()
13973     * @apiName finishOnlineLesson
13974     * @apiGroup Waiting
13975     * @apiDescription Finishes an online lesson for the authenticated user in Native Camp. It retrieves lesson details, updates lesson status, and returns the lesson summary.
13976     *
13977     * @apiBody {String} chatHash The chat hash of the lesson.
13978     * 
13979     * @apiSuccess {Boolean} lessonHistoryExist Indicates whether the lesson history exists.
13980     * @apiSuccess {String} ageRange The age range of the user.
13981     * @apiSuccess {Object} logDetail The lesson log details.
13982     * @apiSuccess {Object} lessonOnAirData The lesson on-air data.
13983     * @apiSuccess {Object} teacherDetailData The teacher detail data.
13984     * @apiSuccess {Object} teacherData The teacher data.
13985     * @apiSuccess {Array} avatarTeacherIdArr The array of avatar teacher IDs.
13986     * @apiSuccess {String} teacherName The name of the teacher.
13987     * @apiSuccess {String} teacherNameJA The Japanese name of the teacher.
13988     * @apiSuccess {String} teacherImage The image URL of the teacher.
13989     * @apiSuccess {String} urlLink The URL link to the teacher's detail page.
13990     * @apiSuccess {String} favTeaherId The favorite teacher ID.
13991     * @apiSuccess {String} counselorImageUrl The image URL of the counselor.
13992     * @apiSuccess {String} textbookImage The image URL of the textbook.
13993     * @apiSuccess {String} courseTitle The title of the course.
13994     * @apiSuccess {String} subCategoryLabel The label of the subcategory.
13995     * @apiSuccess {String} chapterTitle The title of the chapter.
13996     * @apiSuccess {Boolean} lessonTrouble Indicates whether there was a lesson trouble.
13997     * @apiSuccess {String} userToken The user token.
13998     * @apiSuccess {Object} finishLessonUser The user data.
13999     * @apiSuccess {String} chat_hash The chat hash of the lesson.
14000     * @apiSuccess {Boolean} lesson_review_flg Indicates whether the lesson review flag is set.
14001     * @apiSuccess {Boolean} isDefaulTextbook Indicates whether the textbook is the default textbook.
14002     * @apiSuccess {Boolean} firstSelectedDummy Indicates whether the first selected textbook is a dummy.
14003     * @apiSuccess {Boolean} allowEvaluation Indicates whether the teacher evaluation is allowed.
14004     * @apiSuccess {Object} getActiveCampaign The active campaign data.
14005     * @apiSuccess {Boolean} firstLesson Indicates whether it is the first lesson.
14006     * @apiSuccess {Boolean} hideTextbookChangeModal Indicates whether to hide the textbook change modal.
14007     * @apiSuccess {String} textbookCategoryType The type of the textbook category.
14008     * @apiSuccess {String} memberType The type of the member.
14009     * @apiSuccess {String} nickname The nickname of the user.
14010     * @apiSuccess {Number} textbookCategoryId The ID of the textbook category.
14011     * @apiSuccess {Number} isLiveFlg Indicates whether the lesson is live.
14012     * @apiSuccess {Boolean} lessonReviewModalOn Indicates whether the lesson review modal is on.
14013     * @apiSuccess {String} user_language The language of the user.
14014     *
14015     * @apiSuccessExample {json} Success-Response:
14016     *     {
14017     *         "lessonHistoryExist": true,
14018     *         "ageRange": "20-30",
14019     *         "logDetail": {...},
14020     *         "lessonOnAirData": {...},
14021     *         "teacherDetailData": {...},
14022     *         "teacherData": {...},
14023     *         "avatarTeacherIdArr": [...],
14024     *         "teacherName": "John Doe",
14025     *         "teacherNameJA": "ジョン・ドウ",
14026     *         "teacherImage": "http://example.com/image.jpg",
14027     *         "urlLink": "/waiting/detail/1",
14028     *         "favTeaherId": "1",
14029     *         "counselorImageUrl": "http://example.com/counselor.jpg",
14030     *         "textbookImage": "http://example.com/textbook.jpg",
14031     *         "courseTitle": "Course Title",
14032     *         "subCategoryLabel": "Subcategory Label",
14033     *         "chapterTitle": "Chapter Title",
14034     *         "lessonTrouble": false,
14035     *         "userToken": "example_token",
14036     *         "finishLessonUser": {...},
14037     *         "chat_hash": "example_chat_hash",
14038     *         "lesson_review_flg": 1,
14039     *         "isDefaulTextbook": false,
14040     *         "firstSelectedDummy": false,
14041     *         "allowEvaluation": 1,
14042     *         "getActiveCampaign": {...},
14043     *         "firstLesson": false,
14044     *         "hideTextbookChangeModal": "false",
14045     *         "textbookCategoryType": "Type",
14046     *         "memberType": "student",
14047     *         "nickname": "nickname",
14048     *         "textbookCategoryId": 1,
14049     *         "isLiveFlg": 0,
14050     *         "lessonReviewModalOn": false,
14051     *         "user_language": "en"
14052     *     }
14053     *
14054     * @apiError {String} error Message indicating the error.
14055     *
14056     * @apiErrorExample {json} Error-Response:
14057     *     {
14058     *         "error": "Invalid request."
14059     *     }
14060     * 
14061     * @apiSampleRequest off
14062     */
14063    public function finishOnlineLesson() {
14064        $this->autoRender = false;
14065        $this->layout = false;
14066        if ($this->request->is('ajax')) {
14067            $chatHash = $this->request->data('chatHash');
14068        
14069            // 4372 textbook name cached
14070            $memcached = new myMemcached();
14071            $textbookNamesCached = $memcached->get(Configure::read('textbook_names_cache_key'));
14072
14073            $userId = $this->Auth->user('id');
14074            $this->Session->delete('lesson.proceedFlg');
14075            //CheckHash
14076            $this->LessonOnairsLog->openDBReplica();
14077            $allData = $this->LessonOnairsLog->find('first', $this->checkHash('LessonOnairsLog',$chatHash));
14078            $lessonHistoryExist = true;
14079            $this->LessonOnairsLog->closeDBReplica();
14080            if(!$allData) { // if LessonOnairsLog's chat_hash returns null/empty , retrieve record from lessonOnair
14081                $this->LessonOnair->openDBReplica();
14082                $allData = $this->LessonOnair->find('first', $this->checkHash('LessonOnair',$chatHash));
14083                $lessonHistoryExist = false;
14084                $this->LessonOnair->closeDBReplica();
14085                if(!$allData) {
14086                    die();
14087                }
14088            }
14089
14090            $response['lessonHistoryExist'] = $lessonHistoryExist;
14091            $userValidForSSBEDT = false;
14092            if (isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')){
14093                $userValidForSSBEDT = true;
14094            }
14095
14096            $param = array( 
14097                "user_id" => $userId,
14098                "select_method" => "first",
14099                "env_flag" => "all",
14100                'connect_id' => $allData['Connect']['id'],
14101                "user_locale" => $this->localizeDir,
14102                "userValidForSSBEDT" => $userValidForSSBEDT
14103            );
14104            $textbookData = $this->Textbook->getTextbooks($param);
14105            
14106            $lessonUserData = (isset($allData['User'])) ? new UserTable($allData['User']) : null;
14107            
14108            $response['ageRange'] = $lessonUserData->getAgeRange();
14109            $response['logDetail'] = new LessonOnairsLogTable($allData['LessonOnairsLog']);
14110            if(isset($allData['LessonOnairsLog'])) {
14111                $response['lessonOnAirData'] = new LessonOnairsLogTable($allData['LessonOnairsLog']);
14112
14113            } else if(isset($allData['LessonOnair'])) {
14114                $response['lessonOnAirData'] = new LessonOnairTable($allData['LessonOnair']);
14115            } else {
14116                $response['lessonOnAirData'] = null;
14117            }
14118            $teacherData = new TeacherTable($allData['teacher']);
14119            $response['teacherDetailData'] = new TeacherDetailTable($allData['TeacherDetail']);
14120            
14121            $response['teacherData'] = $teacherData;
14122            $response['avatarTeacherIdArr'] = Configure::read("default_avatar_detail");
14123            $response['teacherName'] = $teacherData->name;
14124            $response['teacherNameJA'] = $teacherData->jp_name;
14125            $response['teacherImage'] = $teacherData->getImageUrl();
14126            $response['urlLink'] = "/waiting/detail/".$teacherData->getId();
14127            $response['favTeaherId'] = $teacherData->id;
14128            if ($teacherData->counseling_flg) {
14129                $counselorImageUrl = $teacherData->getProfileImage(Configure::read('default_counselor_detail'));
14130                $response['counselorImageUrl'] = $counselorImageUrl;
14131                $response['teacherName'] = "Counselor";
14132                $response['teacherNameJA'] = "カウンセラー";
14133                $response['teacherImage'] = $counselorImageUrl['image_url'];
14134                $response['urlLink'] = "/counselor_detail";
14135            }
14136            // avatar teacher
14137            if ($teacherData->avatar_id && $teacherData->avatar_flg) {
14138                if ($teacherData->avatar_id) {
14139                    $response['teacherName'] = $teacherData->getAvatarParentNameEn();
14140                    $response['teacherNameJA'] =  $teacherData->getAvatarParentName();
14141                    $response['teacherImage'] = $teacherData->getAvatarParentImageUrl();
14142                    $response['favTeaherId'] = $teacherData->avatar_id;
14143                    $response['urlLink'] = "/avatar_detail/".$teacherData->avatar_id;
14144                }
14145            }
14146
14147            $data = $textbookData['res_data'];
14148            $order = (isset($textbookNamesCached[$data['TextbookConnect']['id']]['order']) && $textbookNamesCached[$data['TextbookConnect']['id']]['order']) ? $textbookNamesCached[$data['TextbookConnect']['id']]['order'] : '';
14149
14150            //- check if for live viewing
14151            $onairData = isset($allData['LessonOnairsLog']) ? $allData['LessonOnairsLog'] : $allData['LessonOnair'];
14152            $onAirUserId = $onairData['user_id'];
14153            $isLive = $onairData['live_lesson_flg'];
14154
14155            //- check member type
14156            $memberType = 'student';
14157            $liveSystemTrouble = 0;
14158
14159            if ($isLive && $onAirUserId != $userId) {
14160                $memberType = 'viewer';
14161                //- update end time
14162                $this->LessonOnairsViewersLog->endTime([
14163                    'chat_hash'     => $chatHash,
14164                    'user_id'         => $userId,
14165                    'guest_viewer'     => empty($userId) ? 1 : 0,
14166                    'viewer_ip'         => myTools::getClientIP()
14167                ]);
14168
14169                $liveLog = $this->LessonOnairsViewer->find('first', [
14170                    'fields' => [
14171                        'LessonOnairsViewer.live_system_trouble'
14172                    ],
14173                    'conditions' => [
14174                        'LessonOnairsViewer.user_id' => $userId,
14175                        'LessonOnairsViewer.chat_hash' => $chatHash
14176                    ]
14177                ]);
14178                $liveSystemTrouble = (!empty($liveLog['LessonOnairsViewer']['live_system_trouble'])) ? 1 : 0;
14179
14180                if ($liveLog) {
14181                    // process live lesson coupon grant
14182                    $this->LessonOnairsViewer->processLiveLessonCouponGrant($this->sharedUserData['User'], $chatHash);
14183                }
14184            }
14185
14186            $userValidForSSBEDT = false;
14187            if (isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')){
14188                $userValidForSSBEDT = true;
14189            }
14190            $param = array(
14191                "user_id" => $userId,
14192                "select_method" => "first",
14193                "env_flag" => "all",
14194                'connect_id' => $allData['Connect']['id'],
14195                "user_locale" => $this->localizeDir,
14196                "userValidForSSBEDT" => $userValidForSSBEDT
14197            );
14198            //NJ-12326
14199            if ($userId && isset($allData['Connect']['category_id']) && $allData['Connect']['category_id']) {
14200                $corporateParams = array('user_id' => $userId);
14201                $corporateTextbookControlFlg = $this->Corporate->getCorporateTextbookControl($corporateParams);
14202
14203                if ($corporateTextbookControlFlg == 1) {
14204                    $categoryData = $this->TextbookCategory->getKidsCategoryTypesById($allData['Connect']['category_id']);
14205                    if (!empty($categoryData)) {
14206                        $param['include_kids_category'] = $allData['Connect']['category_id'];
14207                    }
14208                }
14209            }
14210            $textbookData = $this->Textbook->getTextbooks($param);
14211
14212            $data = $textbookData['res_data'];
14213
14214            // textbook image
14215            $response['textbookImage'] = $data['TextbookCategory']['image_small_url'];
14216
14217            $order = (isset($textbookNamesCached[$data['TextbookConnect']['id']]['order']) && $textbookNamesCached[$data['TextbookConnect']['id']]['order']) ? $textbookNamesCached[$data['TextbookConnect']['id']]['order'] : '';
14218            
14219            $courseTitle = (isset($data['TextbookCategory']['name'])) ? $data['TextbookCategory']['name'] : '';
14220            $subCategoryNameLabel = (isset($data['TextbookSubcategory']['name'])) ? $data['TextbookSubcategory']['name'] : '';
14221            $chapterTitle = isset($textbookNamesCached[$data['TextbookConnect']['id']]['jpn'] ) ?  $textbookNamesCached[$data['TextbookConnect']['id']]['jpn'] : ((isset($data['Textbook']['name'])) ? $order.$data['Textbook']['name'] : '');
14222
14223            #global textbook information
14224            $globalCourseTitle = isset($data['GlobalTextbookCategory']['gl_name']) ? $data['GlobalTextbookCategory']['gl_name'] : $courseTitle;
14225            $subCategoryNameLabel = isset($data['GlobalTextbookSubcategory']['gl_name']) ? $data['GlobalTextbookSubcategory']['gl_name'] : $subCategoryNameLabel;
14226            $globalChapterTitle = isset($data['GlobalTextbook']['gl_name']) ? $order.$data['GlobalTextbook']['gl_name'] : $chapterTitle;
14227
14228            // check for main topic
14229            if ( isset($data['Textbook']['main_topic_id']) && $data['Textbook']['main_topic_id'] ) {
14230                $langId = ClassRegistry::init('CountryCode')->getUserLanguageId($this->localizeDir);
14231                $textbookMainTopicName = ClassRegistry::init('Textbook')->getTextbookMainTopicName($data['Textbook']['id'],$langId);
14232                if ($textbookMainTopicName) {
14233                    $subCategoryNameLabel = $textbookMainTopicName;
14234                }
14235            }
14236
14237            //get teacher id from logs
14238            $teacherId = isset($allData['LessonOnairsLog']['teacher_id']) ? $allData['LessonOnairsLog']['teacher_id'] : $allData['LessonOnair']['teacher_id']; 
14239
14240            // - check if the queried data has teacher rank coin id
14241            if(isset($allData['teacher']['rank_coin_id'])) {
14242                $teacher_rank_coin_id = $allData['teacher']['rank_coin_id'];
14243
14244            } else {
14245                // - get teacher rank coin id
14246                $this->Teacher->openDBReplica();
14247                $coinId = $this->Teacher->find('first',array(
14248                    'fields' => array('Teacher.rank_coin_id'),
14249                    'conditions' => array('Teacher.id' => $teacherId),
14250                    'recursive' => -1
14251                ));
14252                $this->Teacher->closeDBReplica();
14253                $teacher_rank_coin_id = isset($coinId['Teacher']['rank_coin_id']) ? $coinId['Teacher']['rank_coin_id'] :  null;
14254
14255            }
14256
14257            $showRatingFlg = $this->TeacherRankCoin->find('first',array(
14258                    'fields' => array('TeacherRankCoin.strength_weakness_flag', 'TeacherRankCoin.id'),
14259                    'conditions' => array('TeacherRankCoin.id' => $teacher_rank_coin_id)
14260                ));
14261            $response['showRatingFlg'] = $showRatingFlg['TeacherRankCoin']['strength_weakness_flag'];
14262
14263            $user = (isset($this->sharedUserData['User'])) ? new UserTable($this->sharedUserData['User']) : null;
14264            $response['userMembershipIndex'] = null;
14265            if (!empty($user)) {
14266                $userMembershipIndex = $user->getMembershipTypeIndex();
14267                $response['userMembershipIndex'] = $userMembershipIndex;
14268            }            
14269
14270            $noNextTextbookModal = array(
14271                11, //'Corporate Limited Plan(Company payment-Bank transfer)'
14272                35, //'Study Sapuri ENGLISH School Plan (Paid)',
14273                16, //'Corporate Light Plan(Company payment-Bank transfer)',
14274                25, //'Corporate Light Plan (Company payment-Card)',
14275                17, //'Corporate Light Plan (Individual payment)',
14276            );
14277
14278            $response['noNextTextbookModal'] = $noNextTextbookModal;
14279
14280            $counselorDetail = $this->Teacher->getDefaultCounselorDetail();
14281            $this->set('counselorDetail', $counselorDetail);
14282
14283            if (is_null($allData['teacher']['first_lesson_date'])) {
14284                if (isset($allData['LessonOnair'])) {
14285                    $allData['teacher']['first_lesson_date'] = $allData['LessonOnair']['end_time'];
14286                } elseif (isset($allData['LessonOnairsLog'])) {
14287                    $allData['teacher']['first_lesson_date'] = $allData['LessonOnairsLog']['end_time'];
14288                }
14289            }
14290
14291            //NC-4572
14292            $userID = $this->Auth->user('id');
14293
14294            $lessonTrouble = isset($allData['LessonOnairsLog']['lesson_system_trouble']) ? intval($allData['LessonOnairsLog']['lesson_system_trouble']) : intval($allData['LessonOnair']['lesson_system_trouble']); 
14295
14296            $response['lessonTrouble'] =  ($lessonTrouble || $liveSystemTrouble);
14297            $response['userToken'] = $this->Auth->user('api_token');
14298            $response['courseTitle'] = $globalCourseTitle;
14299            $response['subCategoryLabel'] = $subCategoryNameLabel;
14300            $response['chapterTitle'] = $globalChapterTitle;
14301            $response['finishLessonUser'] = $user;
14302            $response['chat_hash'] = $chatHash;
14303            $response['lesson_review_flg'] = isset($user->lesson_review_flg) ? $user->lesson_review_flg : 0;
14304
14305            // NJ-8416
14306            $env = Configure::read('ENVIRONMENT');
14307            $defaultTextbookId = Configure::read("default_dummy_textbook.{$env}");
14308            $dummyConnectId = Configure::read("dummy_textbook_connect_id.{$env}");
14309
14310            // - check end lesson textbook is dummy
14311            $isDefaulTextbook = ($defaultTextbookId == $allData['Connect']['category_id']) ? true : false;
14312
14313            $response['isDefaulTextbook'] = $isDefaulTextbook;
14314
14315            // - get first selected textbook connect_id
14316            $userFirstSelectedTextbook = $this->User->getUserData(
14317                array(
14318                    'id' => $userId
14319                ),
14320                array(
14321                    'first_selected_textbook'
14322                ),
14323                'first'
14324            );
14325
14326            // - check first selected textbook connect_id is dummy
14327            $firstSelectedDummy = ($userFirstSelectedTextbook['User']['first_selected_textbook'] == $dummyConnectId) ? true : false;
14328            $response['firstSelectedDummy'] = $firstSelectedDummy;
14329
14330
14331            // NJ-33170
14332            $lessonConnectId = isset($allData['LessonOnairsLog']['connect_id']) && $allData['LessonOnairsLog']['connect_id'] ? $allData['LessonOnairsLog']['connect_id'] : $allData['LessonOnair']['connect_id'];
14333            // get lesson textbook category id
14334            $this->TextbookConnect->openDbReplica();
14335            $textbookConnect = $this->TextbookConnect->find('first', array(
14336                'fields' => array('TextbookConnect.category_id'),
14337                'conditions' => array('TextbookConnect.id' => $lessonConnectId)
14338            ));
14339            $this->TextbookConnect->closeDbReplica();
14340            $lessonTextbookCategoryId = isset($textbookConnect['TextbookConnect']['category_id']) ? $textbookConnect['TextbookConnect']['category_id'] : null;
14341            
14342            $teacherEvalRestrictedTextbook = Configure::read("teacher_evaluation_restricted_textbook.{$env}");
14343            // disable teacher textbook evaluation if textbook is: (Textbook selection after entering the lesson)
14344            $allowEvaluation = $lessonTextbookCategoryId == $teacherEvalRestrictedTextbook ? 0 : 1;
14345
14346            $response['allowEvaluation'] = $allowEvaluation;
14347
14348            // [START]--- Campaign modal
14349            $getActiveCampaignParams = array(
14350                'counseling_flg' => isset($allData['teacher']['counseling_flg']) ? $allData['teacher']['counseling_flg'] : 0,
14351                'avatar_flg' => isset($allData['teacher']['avatar_flg']) ? $allData['teacher']['avatar_flg'] : 0,
14352                'chat_hash' => $chatHash,
14353                'memberType' => $memberType
14354            );
14355            $response['getActiveCampaign'] = $this->getActiveCampaign($getActiveCampaignParams);
14356            // [ END ]--- Campaign modal
14357
14358            // NC-7922 sapuri first lesson
14359            if ($this->studySapuriId) {
14360                $firstLesson = $this->UserFirstLesson->checkFirstLesson(array('user_id' => $userID));
14361                if ($firstLesson && $firstLesson['UserFirstLesson']['chat_hash'] == $chatHash) {
14362                    $oUserData = new UserTable($this->sharedUserData['User']);
14363                    $sapuriPlan = $oUserData->isStudySapuri();
14364                    $stusapTextType = Configure::read('studysapuri_textbook_category_types');
14365                    $topList = $this->CommonTeacherStatus->getSapuriRecommendTeacher($stusapTextType[$sapuriPlan]);
14366                    $firstLesson = true;
14367
14368                    $response['reserveRecommend'] = $topList;
14369                } else {
14370                    $firstLesson = false;
14371                }
14372            } else {
14373                $firstLesson = false;
14374            }
14375
14376            $response['firstLesson'] = $firstLesson;
14377
14378            // NC-7592 - Hide textbookChange modal after lesson if reserved lesson & disable button if no next textbook chapter
14379            $isReservedLesson = 2;
14380            $hideTextbookChangeModal = $enableNextTextbookChapterButton = 'false';
14381            $latestPresetTextbookConnect_id = (int)$data['TextbookConnect']['id'];
14382
14383            //NJ-3626 Optimize PC /lesson-finish page
14384            $lessonOnairLatestData = $this->LessonOnair->getLatestLessonOnairDetailsOfUserAndTeacher($userId, $teacherId);
14385            $lessonOnairLatestDataFlg = false;
14386            if(isset($lessonOnairLatestData) && $lessonOnairLatestData) {
14387                $lessonOnairLatestDataFlg = true;
14388                $lessonOnairLatest_connectId = (int)$lessonOnairLatestData['LessonOnair']['connect_id'];
14389                $lessonOnairLatest_lessonType = (int)$lessonOnairLatestData['LessonOnair']['lesson_type'];
14390            } else {
14391                $lessonOnairLogsLatestData = $this->LessonOnairsLog->getLatestLessonLogsDetailsOfUserAndTeacher($userID, $teacherId);
14392                if(isset($lessonOnairLogsLatestData) && $lessonOnairLogsLatestData) {
14393                    $lessonOnairLogsLatest_connectId = (int)$lessonOnairLogsLatestData['LessonOnairsLog']['connect_id'];
14394                    $lessonOnairLogsLatest_lessonType = (int)$lessonOnairLogsLatestData['LessonOnairsLog']['lesson_type'];
14395                }
14396            }
14397
14398            // - initialize empty variable
14399            $isLatestPresetTextbookMadeDuringLastLesson = [];
14400            $latestPresetTextbookParams = [];
14401
14402            // For hiding of textbookchange modal (if reserved lesson & not studySapuri)
14403            if ($lessonOnairLatestDataFlg) {
14404                $latestPresetTextbookParams = array (
14405                    'userId' => $userID,
14406                    'latestPresetTextbookConnect_id' => $latestPresetTextbookConnect_id,
14407                    'lessonOnairLatest_startTime' => $lessonOnairLatestData['LessonOnair']['start_time'],
14408                    'lessonOnairLatest_endTime' => $lessonOnairLatestData['LessonOnair']['end_time']
14409                );
14410
14411            // - if has lesson onairs log
14412            } else if ($lessonOnairLogsLatestData) {
14413                $latestPresetTextbookParams = array (
14414                    'userId' => $userID,
14415                    'latestPresetTextbookConnect_id' => $latestPresetTextbookConnect_id,
14416                    'lessonOnairLogsLatest_startTime' => $lessonOnairLogsLatestData['LessonOnairsLog']['start_time'],
14417                    'lessonOnairLogsLatest_endTime' => $lessonOnairLogsLatestData['LessonOnairsLog']['end_time']
14418                );
14419
14420            }
14421
14422            $response['isStudySapuriTosUser'] = $this->isStudySapuriTosUser;
14423            // - if has parameters for fetching latest textbook parameters
14424            if ($latestPresetTextbookParams) {
14425                $isLatestPresetTextbookMadeDuringLastLesson = $this->UsersTextbookInfo->checkLatestUserTextbookInfoChangedDuringLesson($latestPresetTextbookParams);
14426            }
14427
14428            // -  check sapuri ID
14429            if(!isset($this->studySapuriId) || !$this->studySapuriId) {
14430                if (isset($lessonOnairLatestDataFlg)) {
14431                    if (is_array($isLatestPresetTextbookMadeDuringLastLesson) && !empty($isLatestPresetTextbookMadeDuringLastLesson)
14432                        && $latestPresetTextbookConnect_id == $lessonOnairLatest_connectId && $lessonOnairLatest_lessonType == $isReservedLesson
14433                    ) {
14434                        $hideTextbookChangeModal = 'true';
14435                    }
14436                } else {
14437                    if (
14438                        is_array($isLatestPresetTextbookMadeDuringLastLesson) && !empty($isLatestPresetTextbookMadeDuringLastLesson)
14439                        && $latestPresetTextbookConnect_id == $lessonOnairLogsLatest_connectId &&  $lessonOnairLogsLatest_lessonType == $isReservedLesson
14440                    ) {
14441                        $hideTextbookChangeModal = 'true';
14442                    }
14443                }
14444            }
14445            
14446            // NJ-3696
14447            if($lessonHistoryExist) {
14448                $response['textbookCategoryType'] = $this->TextbookCategory->getTextbookCategoryType($allData['LessonOnairsLog']['textbook_category_id']);
14449            } else {
14450                $response['textbookCategoryType'] = $this->TextbookCategory->getTextbookCategoryType($allData['LessonOnair']['textbook_category_id']);
14451            }
14452
14453            //TODO: NJ-59368 - send is callan textbook category
14454            $response['isCallanTextbook'] = in_array($response['textbookCategoryType'], Configure::read('callan_textbook_type'));
14455
14456            $response['hideTextbookChangeModal'] = $hideTextbookChangeModal;
14457
14458            $response['memberType'] = $memberType;
14459            $response['nickname'] = isset($this->sharedUserData['User']['nickname']) ? $this->sharedUserData['User']['nickname'] : $this->Auth->user('nickname');
14460            $response['textbookCategoryId'] = (int)$allData['Connect']['category_id'];
14461            $response['isLiveFlg'] = (int)$isLive;
14462            $response['lessonReviewModalOn'] = false;
14463            $response['network_review_flg'] = $this->sharedUserData['User']['network_review_flg']; // include the user's setting 'network_review_flg' in the response
14464            if ($this->Auth->User('id')) {
14465                $reviewLessonCache = $memcached->get('lesson-review-modal-'. $chatHash .'-'. $this->Auth->User('id'));
14466                if ($reviewLessonCache !== false && $reviewLessonCache == 1) {
14467                    $response['lessonReviewModalOn'] = true;
14468                }
14469            }
14470            $response['user_language'] = $this->localizeDir;
14471            return json_encode($response);
14472        }
14473        
14474    }
14475
14476    /**
14477     * @api {post} /user/waiting/getCounselorLessonHistory getCounselorLessonHistory()
14478     * @apiName getCounselorLessonHistory
14479     * @apiGroup Waiting
14480     * @apiDescription Retrieves the lesson history for a specific counselor in Native Camp. It returns the lesson history details including textbook information, lesson time, and URLs for chat logs and message logs.
14481     *
14482     * @apiBody {String} teacherId The ID of the teacher.
14483     * 
14484     * @apiSuccess {Boolean} res Indicates whether the request was successful.
14485     * @apiSuccess {Array} lessonHistory The lesson history details.
14486     * @apiSuccess {String} lessonHistory.lesson_number The lesson number.
14487     * @apiSuccess {String} lessonHistory.chatStartJPDate The start date of the chat in Japanese format.
14488     * @apiSuccess {String} lessonHistory.chatStartTime The start time of the chat.
14489     * @apiSuccess {String} lessonHistory.lessonHistoryTime The duration of the lesson in minutes.
14490     * @apiSuccess {String} lessonHistory.textbook_url The URL for the textbook details.
14491     * @apiSuccess {String} lessonHistory.categoryNameLabel The label for the category name.
14492     * @apiSuccess {String} lessonHistory.subCategoryNameLabel The label for the subcategory name.
14493     * @apiSuccess {String} lessonHistory.textbookNameLabel The label for the textbook name.
14494     * @apiSuccess {Number} lessonHistory.rate The rating for the lesson.
14495     * @apiSuccess {String} lessonHistory.chat_logs_url The URL for the chat logs.
14496     * @apiSuccess {Boolean} lessonHistory.has_message_logs Indicates whether the lesson has message logs.
14497     * @apiSuccess {String} lessonHistory.message_logs_url The URL for the message logs.
14498     * @apiSuccess {Number} lessonHistory.audio_count_log The audio count log.
14499     * @apiSuccess {String} lessonHistory.textbook_image The URL for the textbook image.
14500     *
14501     * @apiSuccessExample {json} Success-Response:
14502     *     {
14503     *         "res": true,
14504     *         "lessonHistory": [
14505     *             {
14506     *                 "lesson_number": "1",
14507     *                 "chatStartJPDate": "2023-01-01",
14508     *                 "chatStartTime": "10:00",
14509     *                 "lessonHistoryTime": "30分",
14510     *                 "textbook_url": "/textbook/page-detail/1/1",
14511     *                 "categoryNameLabel": "Category Name",
14512     *                 "subCategoryNameLabel": "Subcategory Name",
14513     *                 "textbookNameLabel": "Textbook Name",
14514     *                 "rate": 5,
14515     *                 "chat_logs_url": "/chat-history/1/1",
14516     *                 "has_message_logs": true,
14517     *                 "message_logs_url": "/lesson-message/detail/1",
14518     *                 "audio_count_log": 1,
14519     *                 "textbook_image": "http://example.com/image.jpg"
14520     *             },
14521     *             ...
14522     *         ]
14523     *     }
14524     *
14525     * @apiError {Boolean} res Indicates whether the request was successful.
14526     *
14527     * @apiErrorExample {json} Error-Response:
14528     *     {
14529     *         "res": false
14530     *     }
14531     * 
14532     * @apiSampleRequest off
14533     */
14534    public function getCounselorLessonHistory() {
14535        $this->autoRender = false;
14536        $this->layout = false;
14537        $response = json_encode(array('res' => false)); // default
14538        
14539        if($this->request->is('post')) {
14540            $post = $this->request->data;
14541            if (!isset($post['teacherId']) && $post['teacherId']) {
14542                return json_encode($response);
14543            }
14544            $teacherId = $post['teacherId'] ?? null;
14545
14546            //NC-7984 start
14547            $lesson_history_data = $this->LessonSchedule->latestCounselorLessonHistory($this->Auth->user('id'), 10);
14548            if(!empty($lesson_history_data) && $lesson_history_data) {
14549                $textbookNamesCachedArr = $lesson_history_data['textbookNamesCachedArr'];
14550
14551                foreach ($lesson_history_data['lessonHistory'] as $key => $value) {
14552                    $dteStart = new DateTime($value['LessonOnairsLog']['start_time']);
14553                    $dteEnd   = new DateTime($value['LessonOnairsLog']['end_time']);
14554
14555                    $logDetail = new LessonOnairsLogTable($value['LessonOnairsLog']);
14556
14557                    $lessonTime = $dteStart->diff($dteEnd);
14558                    $lessonHistoryTime = $lessonTime->format("%I");
14559
14560                    $textbookOrder = isset($textbookNamesCachedArr[$value['TextbookConnect']['id']]['order']) ? $textbookNamesCachedArr[$value['TextbookConnect']['id']]['order'] : '';
14561
14562                    $categoryName = $value['TextbookCategory']['name'];
14563                    $subcategoryName = $value['TextbookSubategory']['name'];
14564                    $textbookName = $value['Textbook']['name'];
14565                    $textbookMainTopicName = isset($value['Textbook']['main_topic_name']) ? $value['Textbook']['main_topic_name'] : '';
14566
14567                    // - if has translated Category name
14568                    if (isset($value['GlobalTextbookCategory']['gl_name']) && $value['GlobalTextbookCategory']['gl_name']) {
14569                        $categoryName = $value['GlobalTextbookCategory']['gl_name'];
14570                    }
14571
14572                    // - if has translated subcategory name
14573                    if (isset($value['GlobalTextbookSubcategory']['gl_name']) && $value['GlobalTextbookSubcategory']['gl_name']) {
14574                        $subcategoryName = $value['GlobalTextbookSubcategory']['gl_name'];
14575                    }
14576
14577                    // - if has translated textbook name
14578                    if (isset($value['GlobalTextbook']['gl_name']) && $value['GlobalTextbook']['gl_name']) {
14579                        $textbookName = $value['GlobalTextbook']['gl_name'];
14580                    }
14581
14582                    // - set textbook name
14583                    $categoryNameLabel = $categoryName;
14584                    $subCategoryNameLabel = $subcategoryName;
14585                    $subCategoryNameLabel = $textbookMainTopicName ? $textbookMainTopicName : $subcategoryName;
14586                    $textbookNameLabel = $textbookOrder . $textbookName;
14587                    $textbook_url = "/textbook/page-detail/{$value['TextbookCategory']['type_id']}/{$value['LessonOnairsLog']['connect_id']}";
14588
14589                    $has_message_logs = !empty($value['LessonOnairsLog']['lesson_memo']) && $value['LessonOnairsLog']['lesson_memo_disp_flg'] == 1 && $value['LessonOnairsLog']['display_message'] == 1;
14590                    $message_logs_url = "/lesson-message/detail/{$value['LessonOnairsLog']['id']}";
14591                    $teacher_id = $value['LessonOnairsLog']['teacher_id'];
14592                    $chat_logs_url = "/chat-history/{$teacher_id}/{$value['LessonOnairsLog']['chat_hash']}";
14593
14594                    $lesson_history_data['lessonHistory'][$key]['lesson_number'] = $value['LessonTrackLogs']['lesson_number'];
14595                    $lesson_history_data['lessonHistory'][$key]['chatStartJPDate'] = $logDetail->chatStartJPDate($this->timeDiffSecond);
14596                    $lesson_history_data['lessonHistory'][$key]['chatStartTime'] = $logDetail->chatStartTime($this->timeDiffSecond);
14597                    $lesson_history_data['lessonHistory'][$key]['lessonHistoryTime'] = $lessonHistoryTime. __('分');
14598                    $lesson_history_data['lessonHistory'][$key]['textbook_url'] = $textbook_url;
14599                    $lesson_history_data['lessonHistory'][$key]['categoryNameLabel'] = $categoryNameLabel;
14600                    $lesson_history_data['lessonHistory'][$key]['subCategoryNameLabel'] = $subCategoryNameLabel;
14601                    $lesson_history_data['lessonHistory'][$key]['textbookNameLabel'] = $textbookNameLabel;
14602                    $lesson_history_data['lessonHistory'][$key]['rate'] = $value['usersClassEvaluations']['rate'];
14603                    $lesson_history_data['lessonHistory'][$key]['chat_logs_url'] = $chat_logs_url;
14604                    $lesson_history_data['lessonHistory'][$key]['has_message_logs'] = $has_message_logs;
14605                    $lesson_history_data['lessonHistory'][$key]['message_logs_url'] = $message_logs_url;
14606                    $lesson_history_data['lessonHistory'][$key]['audio_count_log'] = $value['LessonOnairsLog']['temp_flg1'];
14607                    $lesson_history_data['lessonHistory'][$key]['textbook_image'] = $value['TextbookCategory']['image_big_url'];
14608                }
14609                
14610                $response = json_encode(array(
14611                    'res' => true, 
14612                    'lessonHistory' => $lesson_history_data['lessonHistory']
14613                ));
14614            }
14615        }
14616        return $response;
14617    }
14618
14619    /**
14620     * @api {get} /user/waiting/speakingTestAttendance speakingTestAttendance()
14621     * @apiName speakingTestAttendance
14622     * @apiGroup Waiting
14623     * @apiDescription Retrieves the attendance status for the speaking test and counseling sessions for the authenticated user in Native Camp. It returns the URLs, CSS classes, and text for the speaking test and counseling status.
14624     * 
14625     * @apiSuccess {String} speakingTestDailyFlgUrl The URL for the daily speaking test.
14626     * @apiSuccess {String} speakingTestBusinessFlgUrl The URL for the business speaking test.
14627     * @apiSuccess {String} speakingTestDailyFlgClass The CSS class for the daily speaking test status.
14628     * @apiSuccess {String} speakingTestBusinessFlgClass The CSS class for the business speaking test status.
14629     * @apiSuccess {String} counselingFlgClass The CSS class for the counseling status.
14630     * @apiSuccess {String} speakingTestDailyFlgTxt The text for the daily speaking test status.
14631     * @apiSuccess {String} speakingTestBusinessFlgTxt The text for the business speaking test status.
14632     * @apiSuccess {String} counselingFlgTxt The text for the counseling status.
14633     *
14634     * @apiSuccessExample {json} Success-Response:
14635     *     {
14636     *         "speakingTestDailyFlgUrl": "http://example.com/en/speaking_test/daily_start",
14637     *         "speakingTestBusinessFlgUrl": "http://example.com/en/speaking_test/business_start",
14638     *         "speakingTestDailyFlgClass": "",
14639     *         "speakingTestBusinessFlgClass": "",
14640     *         "counselingFlgClass": "",
14641     *         "speakingTestDailyFlgTxt": "未受験",
14642     *         "speakingTestBusinessFlgTxt": "未受験",
14643     *         "counselingFlgTxt": "未受講"
14644     *     }
14645     *
14646     * @apiError {String} error Message indicating the error.
14647     *
14648     * @apiErrorExample {json} Error-Response:
14649     *     {
14650     *         "error": "Invalid request."
14651     *     }
14652     * 
14653     * @apiSampleRequest off
14654     */
14655    public function speakingTestAttendance(){
14656        $this->autoRender = false;
14657        $this->layout = false;
14658
14659        $speakingTestDailyFlgUrl         = myTools::getUrl() .'/'.$this->localizeDir. "/speaking_test/daily_start";
14660        $speakingTestBusinessFlgUrl     = myTools::getUrl() .'/'.$this->localizeDir. "/speaking_test/business_start";
14661        $speakingTestDailyFlgClass         = '';
14662        $speakingTestBusinessFlgClass     = '';
14663        $counselingFlgClass             = '';
14664        $speakingTestDailyFlgTxt         = __d('waiting', '未受験');
14665        $speakingTestBusinessFlgTxt     = __d('waiting', '未受験');
14666        $counselingFlgTxt                 = __d('waiting', '未受講');
14667
14668        $monthlySpeakingTestStatus = array();
14669        if ( $this->request->is('ajax') && !empty($this->sharedUserData['User']['id']) ) {
14670            $monthlySpeakingTestStatus = UserTable::monthlySpeakingTrainingStatus(array(
14671                'user_id' => $this->sharedUserData['User']['id'],
14672                'time_diff' => $this->timeDiffSecond
14673            ));
14674            //-- Speaking training daily
14675            if (!empty($monthlySpeakingTestStatus['speaking_test_daily_english_flg'])) {
14676                $speakingTestDailyFlgClass         = 'done';
14677                $speakingTestDailyFlgUrl         = myTools::getUrl().'/'.$this->localizeDir. "/speaking_test/daily_start?result=true";
14678                $speakingTestDailyFlgTxt = __d('waiting', '受験済み');
14679            }
14680            //-- Speaking training business
14681            if (!empty($monthlySpeakingTestStatus['speaking_test_business_english_flg'])) {
14682                $speakingTestBusinessFlgClass     = 'done';
14683                $speakingTestBusinessFlgUrl     = myTools::getUrl() .'/'.$this->localizeDir."/speaking_test/business_start?result=true";
14684                $speakingTestBusinessFlgTxt = __d('waiting', '受験済み');
14685            }
14686            //-- Counseling
14687            if (!empty($monthlySpeakingTestStatus['counseling_lesson_flg'])) {
14688                $counselingFlgClass = 'done';
14689                $counselingFlgTxt = __d('waiting', '受講済み');
14690            }
14691
14692            $monthlySpeakingTestStatus = array(
14693                'speakingTestDailyFlgUrl'         => $speakingTestDailyFlgUrl,
14694                'speakingTestBusinessFlgUrl'     => $speakingTestBusinessFlgUrl,
14695                'speakingTestDailyFlgClass'     => $speakingTestDailyFlgClass,
14696                'speakingTestBusinessFlgClass'     => $speakingTestBusinessFlgClass,
14697                'counselingFlgClass'             => $counselingFlgClass,
14698                'speakingTestDailyFlgTxt'         => $speakingTestDailyFlgTxt,
14699                'speakingTestBusinessFlgTxt'     => $speakingTestBusinessFlgTxt,
14700                'counselingFlgTxt'                 => $counselingFlgTxt
14701            );
14702        }
14703        return json_encode($monthlySpeakingTestStatus);
14704    }
14705
14706    /**
14707     * @api {get} /user/waiting/getRegion getRegion()
14708     * @apiName getRegion
14709     * @apiGroup Waiting
14710     * @apiDescription Retrieves the list of countries and their regions based on the user's language in Native Camp. It returns the country and region details.
14711     *
14712     * @apiSuccess {Boolean} success Indicates whether the request was successful.
14713     * @apiSuccess {Array} regionDetails The list of countries and their regions.
14714     * @apiSuccess {Object} regionDetails.country The details of a country.
14715     * @apiSuccess {String} regionDetails.country.country_name The name of the country.
14716     * @apiSuccess {Array} regionDetails.country.regions The list of regions in the country.
14717     * @apiSuccess {Object} regionDetails.country.regions.region The details of a region.
14718     * @apiSuccess {String} regionDetails.country.regions.region.id The ID of the region.
14719     * @apiSuccess {String} regionDetails.country.regions.region.region_name The name of the region.
14720     *
14721     * @apiSuccessExample {json} Success-Response:
14722     *     {
14723     *         "success": true,
14724     *         "regionDetails": [
14725     *             {
14726     *                 "country_name": "Japan",
14727     *                 "regions": [
14728     *                     {
14729     *                         "id": "1",
14730     *                         "region_name": "Kanto"
14731     *                     },
14732     *                     ...
14733     *                 ]
14734     *             },
14735     *             ...
14736     *         ]
14737     *     }
14738     *
14739     * @apiError {Boolean} success Indicates whether the request was successful.
14740     * @apiError {String} message The error message.
14741     *
14742     * @apiErrorExample {json} Error-Response:
14743     *     {
14744     *         "success": false,
14745     *         "message": "Failed to retrieve region details."
14746     *     }
14747     * 
14748     * @apiSampleRequest off
14749     */
14750    public function getRegion() {
14751        $this->autoRender = false;
14752
14753        $userLang = $this->localizeDir ? $this->localizeDir : Configure::read('original_language_default');
14754        $languageId = Configure::read('english_language_id'); // set default
14755        $languageIds = $this->CountryCode->getLanguageList(['field'=>'iso_639_1']);
14756
14757        foreach($languageIds as $key => $language) {
14758            if (strtolower($language) == strtolower($userLang)) {
14759                $languageId = $key;
14760                break;
14761            }
14762        }
14763    
14764        $countryRegions = $this->CountryRegion->getCountryResidence([], $languageId, true);
14765        $countryRegionData = array();
14766        
14767        foreach ($countryRegions as $key => $countryRegion) {
14768            $countryRegionData[$countryRegion['CountryCode']['id']]['country_name'] = !empty($countryRegion['GlobalCountryCode']['gl_name']) ? $countryRegion['GlobalCountryCode']['gl_name'] : $countryRegion['CountryCode']['country_name'];
14769            $countryRegionData[$countryRegion['CountryCode']['id']]['regions'][] = [
14770                'id' => $countryRegion['CountryRegion']['id'],
14771                'region_name' => !empty($countryRegion['GlobalCountryRegion']['gl_name']) ? $countryRegion['GlobalCountryRegion']['gl_name'] : $countryRegion['CountryRegion']['region_name']
14772            ];
14773        }
14774
14775        $response = [
14776            'success' => true,
14777            'regionDetails' => array_values($countryRegionData)
14778        ];
14779
14780        return json_encode($response);
14781    }
14782
14783
14784    //get the country and region/city if display flag is on and delete flag is 0 ; 0 = not deleted
14785    function getResidenceData($getCRData) {
14786        $residenceData = [
14787            'countryName' => '',
14788            'countryFlag' => 'other',
14789            'regionName' => ''
14790        ];
14791        if ((empty($getCRData['CountryCode']['country_name']) && empty($getCRData['CountryRegion']['region_name']))) {
14792            return $residenceData;
14793        }
14794        if ($getCRData['CountryCode']['display_flag'] != 1) {
14795            return $residenceData;
14796        }
14797        if (empty($getCRData['TeacherDetail']['country_id'])) {
14798            return $residenceData;
14799        }
14800        if ($getCRData['CountryRegion']['delete_flag'] == 1) {
14801            return $residenceData;
14802        }
14803    
14804        $residenceData['countryName'] = isset($getCRData['GlobalCountryCode']['gl_name']) ? $getCRData['GlobalCountryCode']['gl_name'] : $getCRData['CountryCode']['country_name'];
14805        $getCountryCode = $this->CountryCode->getCountryFromId($getCRData['TeacherDetail']['country_id']);
14806        if ($getCountryCode) {
14807            $countryCodeLower = strtolower($getCountryCode);
14808            $explodeCountryCode = explode(' ', $countryCodeLower);
14809            $residenceData['countryFlag'] = implode('_', $explodeCountryCode);
14810        }
14811    
14812        if (isset($getCRData['GlobalCountryRegion']['gl_name'])) {
14813            $residenceData['regionName'] = $getCRData['GlobalCountryRegion']['gl_name'];
14814        } elseif (isset($getCRData['CountryRegion']['region_name'])) {
14815            $residenceData['regionName'] = $getCRData['CountryRegion']['region_name'];
14816        }
14817
14818        return $residenceData;
14819    }
14820
14821
14822    /**
14823     * @api {post} /user/waiting/countTeacherReservedLessons countTeacherReservedLessons()
14824     * @apiName countTeacherReservedLessons
14825     * @apiGroup Waiting
14826     * @apiDescription Counts the number of reserved lessons for a specific teacher in Native Camp. It checks if the request is an AJAX request and returns the reservation count.
14827     *
14828     * @apiBody {String} teacher_id The ID of the teacher.
14829     * 
14830     * @apiSuccess {Number} reservation_count The number of reserved lessons for the teacher.
14831     *
14832     * @apiSuccessExample {json} Success-Response:
14833     *     {
14834     *         "reservation_count": 5
14835     *     }
14836     *
14837     * @apiError {String} error Message indicating the error.
14838     *
14839     * @apiErrorExample {json} Error-Response:
14840     *     {
14841     *         "error": "Invalid request data."
14842     *     }
14843     * 
14844     * @apiSampleRequest off
14845     */
14846    public function countTeacherReservedLessons(){
14847        $this->autoRender = false;
14848        $this->layout = false;
14849        $reserveCount = array('reservation_count' => 0);
14850
14851        if ( $this->request->is('ajax') && !empty($this->request->data['teacher_id']) ) {
14852            $teacherId = $this->request->data['teacher_id'];
14853            $reserveCount['reservation_count'] = $this->LessonSchedule->countTeacherReservedLessons(array('teacherId' => $teacherId));
14854        }
14855        return json_encode($reserveCount);
14856    }
14857
14858    /**
14859     * Get Live coupon result for viewers
14860     * @param chathash
14861     * @param users_api_token
14862     * @return json
14863     */
14864    public function getLiveCouponResult()
14865    {
14866        $this->autoRender = false;
14867        $this->layout = false;
14868
14869        $users_api_token = $this->request->data['users_api_token'];
14870        $chat_hash = $this->request->data['chat_hash'];
14871        // open tunnel
14872        myTools::initializeApiTunnel(array('LessonDataController'));
14873
14874        // initialize controller
14875        $lcr = new LessonDataController();
14876
14877        // set data
14878        $lcr->params = [
14879            'nc_terminal_type' => 1,
14880            'chat_hash' => $chat_hash,
14881            'users_api_token' => $users_api_token
14882        ];
14883
14884        // process payment
14885        $response = json_decode($lcr->live_coupon_result(), true);
14886        return json_encode($response);    }
14887
14888    public function checkLessonStartButtonNormal() {
14889        $this->autoRender = false;
14890        $this->layout = false;
14891        $user = $this->sharedUserData;
14892        $data = $this->request->data;
14893        $response = [];
14894        $ua = myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']) ?? '';
14895        $env = Configure::read('ENVIRONMENT');
14896
14897        if(empty($data['teacherId'])) {
14898            $response['error'] = 'Invalid parameters!';
14899            return json_encode($response);
14900        }
14901
14902        $studentId = (int) $data['studentId'];
14903        $teacherId = (int) $data['teacherId'];
14904        $counselingFlg = $data['counselingFlg'] ?? 0;
14905        myTools::initializeApiTunnel(array('TeachersDetailController'));
14906        $TeachersDetailController = new TeachersDetailController();
14907        $TeachersDetailController->params = [
14908            'nc_terminal_type' => 1, // pc
14909            'users_api_token' => $user['User']['api_token'],
14910            'teachers_id' => (int) $data['teacherId'],
14911            'la' => $data['la']
14912        ];    
14913        $api = json_decode($TeachersDetailController->detail(), true);        
14914
14915        if (json_last_error() !== JSON_ERROR_NONE) {
14916            $response['error'] = 'Failed to decode API response.';
14917            return json_encode($response);
14918        }
14919
14920        $isGuestViewer = empty($studentId) ? 1 : 0;
14921        $lessonStartBtnText = __d('waiting','今すぐレッスンへ進む');
14922        $lessonStartBtnTextBusy = __d('waiting','取り込み中');
14923        $lessonStartBtnText10minsRemaining = __d('waiting','レッスン終了まで あと%s分');
14924        $lessonOrangeButtonRemaining = false;
14925        $canLessonParam = array(
14926            'homeFlag' => isset($api['CommonTeacherStatus']['Teacher']['home_flg']) ? $api['CommonTeacherStatus']['Teacher']['home_flg'] : null,
14927            'isGuestViwer' => $isGuestViewer
14928        );    
14929        $canLesson = LessonOnairTable::canLesson($teacherId, $studentId, $canLessonParam);
14930        $liveDefault = (object)[
14931            'max_viewer' => Configure::read('max_live_lesson_viewer'),
14932            'lesson_flg' => 0,
14933            'lesson_joined' => 0,
14934            'lesson_started' => 0,
14935            'lesson_finish' => 0
14936        ];
14937        $liveData = isset($canLesson['liveLessonDetail']) && !empty($canLesson['liveLessonDetail']) ? $canLesson['liveLessonDetail'] : $liveDefault;        
14938        
14939        $loginDialog = [
14940            'headerMessage' => __d('login', 'ログインが必要です'),
14941            'message' => __d('login', 'こちらの機能は、ログイン後にご利用いただけます.'),
14942            'loginBtn' =>  __d('login', 'ログインはこちら'),
14943            'registerBtn' => __d('login', '新規会員登録はこちら')
14944        ];
14945        $json = [
14946            'lessonStartBtnText' => $lessonStartBtnText,
14947            'lessonStartBtnTextBusy' => $lessonStartBtnTextBusy,
14948            'lessonStartBtnText10minsRemaining' => $lessonStartBtnText10minsRemaining,
14949            'isGuestViewer' => (bool) $isGuestViewer,
14950            'loginDialog' => $loginDialog,
14951            'fullBaseUrl' => $this->baseUrl,
14952            'canLesson' => $canLesson
14953        ];
14954        $remainingLessonTime = 0;
14955        
14956        $canMidwayLesson = false;
14957        $isViewer = 0;
14958        $onair = $api['LessonOnair'];
14959        $hasRemainingLife = false;
14960        $unsupportedBrowser = false;
14961        $browser = $this->request->header('User-Agent');
14962
14963        if (preg_match('/(Edg|Edge)/i',$browser) ) {
14964            $unsupportedBrowser = false;
14965        } elseif (preg_match('/(OPR)/i',$browser)) {
14966            $unsupportedBrowser = true;
14967        } elseif (preg_match('/(Chrome|Firefox|Safari)/i',$browser)) {
14968            $unsupportedBrowser = false;
14969        } else {
14970            $unsupportedBrowser = true;
14971        }
14972
14973        $currentMin = date('i');
14974
14975        if (($currentMin >= 25 && $currentMin < 30) || ($currentMin >= 55 && $currentMin <= 59)) {
14976            $reservedId = isset($canLesson['nextReservation']['user_id']) ? $canLesson['nextReservation']['user_id'] : null;
14977        } else {
14978            $reservedId = isset($canLesson['currentReservation']['user_id']) ? $canLesson['currentReservation']['user_id'] : null;
14979        }
14980
14981        if(
14982            $liveData->lesson_flg && 
14983            (
14984                (
14985                    !is_null($onair['user_id']) &&
14986                    $onair['user_id'] == $studentId
14987                )
14988                ||
14989                (
14990                    is_null($onair['user_id']) &&
14991                    $reservedId &&
14992                    $reservedId != $studentId
14993                )
14994            )
14995        ) {
14996            $isViewer = 1;
14997        }
14998
14999        if(!$isGuestViewer) {        
15000            if(!empty($api['error'])) {
15001                $json['api_error'] = $api['error'];
15002                return json_encode($json);
15003            }
15004
15005            $buttonStates = array_flip(Configure::read('user_detail_state_button'));
15006            $stateButton = $api['teacher']['state_button'];
15007            $teacherStatusOnAir = $api['LessonOnair'] ?? null;
15008            $_teacherStatus = $api['TeacherStatus'];
15009            $reservedLessonData = $api['reservedLessonData'];
15010            $isReserved = $api['isReserved'];
15011            $teacher = $api['CommonTeacherStatus']['Teacher'];
15012            $remainingLessonTime = $api['remainingLessonTime'];
15013            $checkBadge = $api['checkBadge'];
15014            $teacherStatus = !empty($_teacherStatus) && empty($teacherStatusOnAir) ? $_teacherStatus : $teacherStatusOnAir;
15015            $_paymentPlanID = isset($user['User']['payment_plan_id']) ? $user['User']['payment_plan_id'] : null;
15016            $isNormalLitePlanUser = (in_array($_paymentPlanID, Configure::read('lite_payment_plans') ) ) ? true : false;
15017            $stateButtonAddntlCheck = Configure::read('user_detail_state_button_addntl_check');
15018            $userNotEligible = false;
15019            $lessonType = false;
15020            $lessonOnOther = false;
15021            $lessonStartBtnText = $isNormalLitePlanUser ? __d('waiting','予約専用です') : __d('waiting','今すぐレッスンへ進む');
15022            $userDuplicateLesson = false;
15023            $isReservedCanSuddenLesson = false;
15024            $isReservedCanLessonViewing = false;
15025            $userAdminFlag = isset($user['User']['admin_flg']) ? $user['User']['admin_flg'] : '';
15026            $userFailFlag = isset($user['User']['fail_flg']) ? $user['User']['fail_flg'] : '';
15027            $userDoubleCheckFlag = isset($user['User']['double_check_flg']) ? $user['User']['double_check_flg']: '';
15028            $userCardCompany = isset($user['User']['card_company']) ? $user['User']['card_company']: '';
15029            $corporateUserFlg = isset($user['User']['corporate_id']) ? $user['User']['corporate_id'] : false;
15030            $isEmergencyLesson = (isset($data['emergencyFlg']) && $data['emergencyFlg']) ? true : false;
15031            $hasLessonBeforeActualTime = false;
15032            $teacherStatusColor = '';
15033            $ownReservationFlg = 0;
15034            $liveStatus = 0;
15035            $isBusy = false;
15036            $use7DaysTrialModal = false;
15037            $redirectPlanUrl = '';
15038            $teacherLeaveNotice = '';
15039            $showNativeSpeakerWarning = false;
15040            $baseUrl = myTools::getUrl($this->localizeDir);
15041
15042            // get reservation
15043            $nextReservation = LessonScheduleTable::getReservation(array(
15044                'LessonSchedule.teacher_id' => $api['CommonTeacherStatus']['Teacher']['id'],
15045                'LessonSchedule.user_id' => $data['studentId']
15046            ));
15047
15048            $this->Teacher->unbindModel(array('hasOne' => array('LessonOnair')));
15049            $queryCondition = array(
15050                'fields' => array(
15051                    'TeacherRankCoin.coins',
15052                    'TeacherRankCoin.reserve_coin_settings_flg',
15053                    'LessonOnair.id',
15054                    'LessonOnair.teacher_id',
15055                    'LessonOnair.user_id',
15056                    'TeacherRankCoin.limited_plan_reservation'
15057                ),
15058                'joins' => array(
15059                    array(
15060                        'type' => 'LEFT',
15061                        'table' => 'teacher_rank_coins',
15062                        'alias' => 'TeacherRankCoin',
15063                        'conditions' => array('Teacher.rank_coin_id = TeacherRankCoin.id AND TeacherRankCoin.status')
15064                    )
15065                ),
15066                'conditions' => array(
15067                    array('Teacher.id' => $teacher['id'])
15068                ),
15069                'show' => 'first'
15070            );
15071
15072            $commonTeacherStatusParams = array(
15073                'page_display' => 'listTeacher',
15074                'query_conditions' => $queryCondition
15075            );
15076
15077            $commonTeacher2 = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
15078            $loStatusParams = array(
15079                'LessonOnair' => $commonTeacher2['LessonOnair'],
15080                'Teacher' => $api['CommonTeacherStatus']['Teacher'],
15081                'TeacherStatus' => $api['CommonTeacherStatus']['TeacherStatus'],
15082                'nextReservation' => isset($nextReservation['teacher_id']) ? $nextReservation['teacher_id'] : null,
15083                'userId' => $studentId
15084            );
15085            $teacherStatusNew = LessonOnairTable::teacherStatusColor($loStatusParams);
15086            $teacherStatusColor = TeacherTable::teacherStatusCSS($teacherStatusNew);
15087            $sapuriCoin = $api['teacher']['sapuri_coin'];
15088
15089            if(empty($reservedLessonData)) {
15090                $this->LessonSchedule->recursive = 0;
15091                $reservedLessonData = $this->LessonSchedule->getReservationLessonNow($studentId);
15092            }
15093
15094            // additional state button check from callLessonAlertandStartButton
15095            if(in_array($stateButton, $stateButtonAddntlCheck)) {
15096                // check if lessonOnair is empty
15097                if (isset($api['CommonTeacherStatus']['LessonOnair'])) {
15098                    $tmp = (object) $api['CommonTeacherStatus']['LessonOnair'];
15099                    if (!$tmp->id) {
15100                        $api['CommonTeacherStatus']['LessonOnair'] = null;
15101                    }
15102                }
15103                
15104                // check if lessonOnair contains empty values
15105                $oOnair = !empty($teacherStatus1) && empty($onair) 
15106                            ? new TeacherStatusTable($teacherStatus1) 
15107                            : $onair;    
15108
15109                //get next available schedule
15110                $checkNextSchedule = null;
15111                $checkScheduleCurrent = null;
15112                $lesson_time_stamp = floor(time() / (30 * 60)) * (30 * 60);
15113
15114                if(isset($canLesson['nextReserve'])) {
15115                    $nextSchedule = isset($canLesson['nextReserve']['start']) ? $canLesson['nextReserve']['start'] : null;
15116                    $checkNextSchedule = $nextSchedule ? $this->ShiftWorkOn->checkDataExist($teacherId , $nextSchedule) : null;
15117                    $checkScheduleCurrent = $this->ShiftWorkOn->checkDataExist( $teacherId , date('Y-m-d H:i:s',$lesson_time_stamp));
15118                }
15119
15120                $checkNextSchedule = !empty($checkNextSchedule) ? $checkNextSchedule : false;
15121                $checkScheduleCurrent = !empty($checkScheduleCurrent) ? $checkScheduleCurrent : false;
15122                $nextSchedule = isset($nextSchedule) ? $nextSchedule : '';
15123
15124                // add trappings for meal break, and change $canLesson['nextReserve']['start'] to mealbreak slot if has mealbreak
15125                if (
15126                    (($canLesson['lessonAvailable']
15127                    && !$checkNextSchedule 
15128                    && $checkScheduleCurrent)
15129                    || (isset($canLesson['hasMealbreakNext']) && $canLesson['hasMealbreakNext']))
15130                    && !($api['CommonTeacherStatus']['Teacher']['avatar_parent_flg'] == 1 || $api['CommonTeacherStatus']['Teacher']['avatar_flg'] == 1)
15131                    && !$isEmergencyLesson  # ~don't show in emergency page
15132                    && !$this->isStudySapuriTosUser
15133                    && $api['CommonTeacherStatus']['Teacher']['home_flg'] != 1 // not home based teacher
15134                    && isset($exceedDailyLimit) && !empty($exceedDailyLimit) 
15135                ) {
15136                    $teacherLeaveNotice .= __d('waiting','こちらの講師は'). " ";
15137                    $teacherLeaveNotice .= isset($nextSchedule) ? TimezoneTable::computeTimeToUser(array('time' => strtotime($canLesson['nextReserve']['start']), 'timestamp' => $this->timeDiffSecond, 'format' => 'h:i')) : '';
15138                    $teacherLeaveNotice .= " ". __d('waiting','までのレッスンとなりますので<br>ご了承ください。');
15139                }
15140
15141                // NJ-29831: check if user has reserved lesson for the next 5 min
15142                $scheduleReservationData = $this->LessonSchedule->getScheduledReservationNow($studentId, $teacherId);
15143                $onGoingLesson = $this->LessonOnair->hasOngoingLesson($this->Auth->user('id'));
15144                $hasLessonBeforeActualTime = false;
15145
15146                if (!empty($scheduleReservationData) && !$onGoingLesson) {
15147                    $hasLessonBeforeActualTime = true;
15148                    $isReserved = true;
15149                }
15150    
15151                //get preset textbook or last viewed
15152                $presetParams = array("user_id" => $studentId, 'userValidForSSBEDT' => $this->userValidForSSBEDT());
15153    
15154                //add additional parameter in fetching preset textbook
15155                if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))) {
15156                    $presetParams["lang"] = $this->localizeDir;
15157                }
15158    
15159                $preset_data = $this->UsersTextbookInfo->getPreset($presetParams);
15160                if(isset($preset_data['preset_connect_id']) && !empty($preset_data['preset_connect_id'])) {
15161                    # for preset
15162                    $presetParams['connect_id'] = $preset_data['preset_connect_id'];
15163                    $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
15164    
15165                } else if(isset($preset_data['last_viewed_connect_id']) && !empty($preset_data['last_viewed_connect_id'])) {
15166                    # use last viewed textbook if no preset data.
15167                    $presetParams['connect_id'] = $preset_data['last_viewed_connect_id'];
15168                    $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
15169                }
15170    
15171                // - NJ-3878 : add trapping for pc and app(api) 1 = pc 0 = app
15172                $presetParams['is_pc_flg'] = 1;
15173    
15174                # fetch preset
15175                $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
15176                if(!$preset) {
15177                    unset($presetParams['connect_id']);
15178                    unset($presetParams['last_opened_date']);
15179                    $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
15180                }
15181    
15182                $lessonData = $preset["textbook_info"];
15183                $categoryId = $lessonData["TextbookCategory"]["id"];
15184                $categoryTypeId = $lessonData["TextbookCategory"]["type_id"];
15185                $textbookId = $lessonData["Textbook"]["id"];
15186                
15187                if( $categoryTypeId == 1 ) { // course
15188                    $seriesId = $this->Textbook->getTextbookSeriesId(array( 'textbook_id' => $textbookId ));
15189                } else { // series
15190                    $seriesId = $categoryId;
15191                }
15192
15193                if(empty($checkBadge)) {
15194                    $checkBadge = $this->TeacherBadge->find("first", array(
15195                        "conditions" => array(
15196                            "TeacherBadge.teacher_id" => $teacherId,
15197                            "TeacherBadge.textbook_category_id" => $seriesId
15198                        ),
15199                        "fields" => array("TeacherBadge.id"),
15200                        "recursive" => -1
15201                    ));
15202                }
15203
15204                $canLessonTextbook = $checkBadge || $counselingFlg ? true : false;                
15205
15206                //check if the preset textbook is doesn't have reserve_flg
15207                $textbookForReservationOnly = isset($preset['reservation_flg']) ? $preset['reservation_flg'] : false;
15208                $uOnair = isset($onGoingLesson['LessonOnair']) ? $onGoingLesson['LessonOnair']: '';
15209                $browser =  $this->request->header('User-Agent');
15210                $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($user['User']['payment_plan_id']);
15211
15212                if ($uOnair != null) {
15213                    $uOOnair = new LessonOnairTable($uOnair);
15214                    //check user duplicate lesson
15215                    if ($uOOnair && $uOOnair->status == 3 && $uOOnair->user_id == $this->Auth->User('id') && $uOOnair->teacher_id != $teacherId) {
15216                        $userDuplicateLesson = true;
15217                        $lessonType = $uOOnair->lesson_type;
15218                    }
15219                    //check lesson on others
15220                    if ($oOnair && $oOnair->status == 3 && $oOnair->teacher_id == $teacherId && $oOnair->user_id != $studentId) {
15221                        $lessonOnOther = true;
15222                    }
15223                }
15224
15225                # - [NJ-18003] conditions for terminate reserved lesson for sudden lesson
15226                if (
15227                    $canLessonTextbook &&             # - can lesson with the textbook
15228                    !$textbookForReservationOnly && # - textbook not for reserve only
15229                    !$unsupportedBrowser &&         # - supported browser
15230                    $userDuplicateLesson &&         # - has lesson with other teacher
15231                    $lessonType == Configure::read('lesson.type.reservation') &&
15232                    !$this->isStudySapuriTosUser &&    # - not sapuri TOS user
15233                    !$this->isStudySapuriUser &&    # - not sapuri user
15234                    ($uOnair && $uOnair['leave_lesson']) && # - already left the reserved lesson
15235                    !in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')]) && 
15236                    !in_array($user['User']['payment_plan_id'], Configure::read('payment_plan_lightplan'))  # - not lite plan user
15237                ) {
15238                    $isReservedCanSuddenLesson = true;
15239                }
15240
15241                // if failed settlement -> paid or corporate individual (standard/premium)
15242                if (in_array($this->userMembershipType, Configure::read('membership_type_credit_retry'))) {
15243                    $redirectPlanUrl = $baseUrl . '/payment/payment_credit_retry';
15244                // if free 
15245                } elseif ($this->userMembershipType == Configure::read('membership_type_plan_free')) {
15246                    $redirectPlanUrl = $baseUrl . '/payment/payment_credit_charge';
15247                // if free (trial not yet conducted)
15248                } elseif ($this->userMembershipType == 13) {
15249                    $userNotEligible = 10;
15250                    $use7DaysTrialModal = true;
15251                // if corporate company settlement failed -> standard/premium or
15252                } elseif (in_array($this->userMembershipType, Configure::read('membership_type_corporate_company_failed'))) {
15253                    $redirectPlanUrl = $baseUrl . '/account/contract_information';
15254                }
15255
15256                if( $teacherStatusNew == '5' ) {
15257                    $ownReservationFlg = 1;
15258                }
15259
15260                $membershipTypeReservationOnlyArr = Configure::read('membership_type_blue_btn_reservation_only');
15261                $membershipTypeReservationOnly = false;
15262
15263                if(in_array($this->userMembershipType, $membershipTypeReservationOnlyArr)) {
15264                    $membershipTypeReservationOnly = true;
15265                }
15266
15267                $membershipTypeBlueBtnArr = Configure::read('membership_type_blue_btn');
15268                $membershipTypeBlueBtn = false;
15269
15270                if(in_array($this->userMembershipType, $membershipTypeBlueBtnArr)) {
15271                    $teacherStatusColor = 'wait';
15272                    $membershipTypeBlueBtn = true;
15273                }
15274
15275                $liveLessonFlg = isset($commonTeacher2['LessonOnair']['live_lesson_flg']) ? $commonTeacher2['LessonOnair']['live_lesson_flg'] : 0;
15276
15277                if(!$isGuestViewer && $liveLessonFlg) {
15278                    $reservedLessonData = $api['reservedLessonData'];
15279
15280                    if ($reservedLessonData && $reservedLessonData['Teacher']['id'] != $teacherId) {
15281                        $liveStatus = 0;
15282                    } else {
15283                        //- if lesson started
15284                        if (
15285                            !is_null($api['LessonOnair']['connect_id']) &&
15286                            !is_null($api['LessonOnair']['user_id'])
15287                        ) {
15288                            if ($api['LessonOnair']['user_id'] == $studentId) {
15289                                $liveStatus = 4;
15290                            } else {
15291                                //- check live status
15292                                $liveStatus = $this->LessonOnairsViewer->onGoingLiveStatus([
15293                                    'user_id' => $studentId,
15294                                    'chat_hash' => $api['LessonOnair']['chat_hash']
15295                                ]);
15296
15297                                //-- override status to watch
15298                                if ($liveStatus == 1) {
15299                                    $liveStatus = 2; //view live
15300                                }
15301                            }
15302                        } else {
15303                            $waitingReservationLive = $this->LessonSchedule->getWaitingLiveReservation([
15304                                'teacher_id' => $teacherId
15305                            ]);
15306
15307                            //-has reservation
15308                            if ($waitingReservationLive) {
15309                                if ($waitingReservationLive['LessonSchedule']['user_id'] == $studentId) {
15310                                    $liveStatus = (date('i') >= 0 && date('i') <= 26) || (date('i') >= 30 && date('i') <= 56) ? 4 : 0;
15311                                } else {
15312                                    $liveStatus = 1; //live will start
15313                                }
15314                            }
15315                        }
15316                    }
15317                }
15318
15319                if(!$this->isStudySapuriTosUser) {
15320                    $teacherStudentConnection = $api['teacherStudentConnection'];        
15321                    $teacherStudentData = isset($teacherStudentConnection['TeacherStudentConnection']) ? $teacherStudentConnection['TeacherStudentConnection'] : array();
15322                    if (isset($teacherStudentData['daily_lesson_minutes']) && $teacherStudentData['daily_lesson_minutes']) {
15323                        $exceedDailyLimit = $this->LessonOnair->lessonStartButton(array(
15324                            'teacher_id' => $teacherId,
15325                            'teacherStudentData' => $teacherStudentData,
15326                            'counseling_flg' => isset($commonTeacher2['Teacher']['counseling_flg']) ? $commonTeacher2['Teacher']['counseling_flg'] : 0,
15327                            'avatar_flg' => isset($commonTeacher2['Teacher']['avatar_flg']) ? $commonTeacher2['Teacher']['avatar_flg'] : 0,
15328                            'nickname' => $user['User']['nickname'],
15329                            'admin_flg' => $userAdminFlag,
15330                            'isReserved' => $isReserved,
15331                            'type' => 1
15332                        ));
15333                    }
15334                }
15335
15336                // check if busy
15337                if(isset($exceedDailyLimit) && $exceedDailyLimit && !$isReserved && !$liveData->lesson_flg && !$isGuestViewer) {
15338                    if(empty($teacherStatus->status) || (!empty($teacherStatus->status) && $teacherStatus->status == 1)) {
15339                        $isBusy = true;
15340                    }
15341                }
15342
15343                if(!$isGuestViewer && !isset($remainingLessonTime) || $remainingLessonTime <= 0 || $remainingLessonTime >= 660) {
15344                    $isBusy = true;
15345                }
15346
15347                // NC-5409 : Corporate Limited Plan
15348                if ( isset($corporateType) &&  $corporateType == Configure::read('corporate_type.limited') ) {
15349
15350                    // check if legible
15351                    if (
15352                        (    ($corporateType == Configure::read('corporate_type.limited') && !$isReserved) ||
15353                            (!$isReserved && (!$canLessonTextbook || $textbookForReservationOnly)) ||
15354                            $userDuplicateLesson || 
15355                            $unsupportedBrowser ||
15356                            $lessonOnOther
15357                        ) &&
15358                        $studentId
15359                    ) {
15360                        $userNotEligible = 1;
15361                    }
15362
15363                } elseif ( isset($corporateType) &&  $corporateType == Configure::read('corporate_type.light') ) {
15364
15365                    $corpLightCondition1 = (
15366                        ($corporateType == Configure::read('corporate_type.light') && !$isReserved) ||
15367                        (!$isReserved && (!$canLessonTextbook || $textbookForReservationOnly)) ||
15368                        $userDuplicateLesson ||
15369                        $unsupportedBrowser ||
15370                        $lessonOnOther
15371                    );
15372                    // check if legible
15373                    if ( $corpLightCondition1 && $studentId) {
15374                        $userNotEligible = 2;
15375                    }
15376                } elseif (
15377                    (
15378                        isset($commonTeacher2['Teacher']['native_speaker_flg']) &&
15379                        $commonTeacher2['Teacher']['native_speaker_flg']
15380                    ) &&
15381                    (
15382                        $user['User']['native_option'] == null ||
15383                        $user['User']['native_option'] == 0
15384                    ) &&
15385                    !$isReserved &&
15386                    !$tmp->live_lesson_flg &&
15387                    !$this->isStudySapuriTosUser
15388                ) {
15389                    $userNotEligible = 3;
15390                    $showNativeSpeakerWarning = true;
15391                } elseif ( // NJ-48797
15392                    (isset($getParentAvatarTeacher['Teacher']['native_speaker_flg']) && $getParentAvatarTeacher['Teacher']['native_speaker_flg']) &&
15393                    ($user['User']['native_option'] == null || $user['User']['native_option'] == 0) && 
15394                    !$isReserved &&
15395                    !$tmp->live_lesson_flg &&
15396                    !$this->isStudySapuriTosUser
15397                ) {
15398                    $showNativeSpeakerWarning = true;
15399                    $userNotEligible = 4;
15400                } else {
15401                    // check if legible
15402                    if ((
15403                        (!$isReserved && (!$canLessonTextbook ||$textbookForReservationOnly)) ||
15404                        $userDuplicateLesson || 
15405                        $unsupportedBrowser || 
15406                        (!$userAdminFlag && ($userFailFlag == 1 || $userDoubleCheckFlag == 2)) ||
15407                        $lessonOnOther
15408                    ) && $studentId) {
15409                        $userNotEligible = 5;
15410                    }
15411                }
15412
15413                # ~no sudden lesson for sapuri toS user
15414                if ($this->isStudySapuriTosUser && !$isReserved) {
15415                    $userNotEligible = 6;
15416                }
15417
15418                $_userReservedNowLesson = ($reservedLessonData && $reservedLessonData['Teacher']['id'] == $teacherId) ? true : false;
15419
15420                if (in_array($user['User']['payment_plan_id'],Configure::read('lite_payment_plans')) && !$_userReservedNowLesson && !$isEmergencyLesson) {
15421                    # disable the lesson button for lite plan if it is not reserved lesson
15422                    $userNotEligible = 7;
15423
15424                    # add if reserve is still ongoing 
15425                    if($isReserved) {
15426                        $userNotEligible = false;
15427                    }
15428                }
15429
15430            }            
15431
15432            switch($stateButton) {
15433                case 2: //proceed_to_the_lesson_immediately
15434                    if (!empty($api['CommonTeacherStatus']['user_id']) &&
15435                        $api['CommonTeacherStatus']['user_id'] != $user['id'] &&
15436                        in_array($api['CommonTeacherStatus']['TeacherStatus']['status'], [1, 3])
15437                    ) {
15438                        $stateButton = 5; //busy
15439                    }
15440                    break;
15441                case 3: // go to reserved lesson
15442                case 32: // dummy lesson
15443                    $teacherStatusColor = 'lesson';
15444                case 5: //busy
15445                    if( $teacherStatusColor == 'offline' && $membershipTypeReservationOnly ) {
15446                        $stateButton = 6;
15447                    }
15448                    $teacherStatusColor = 'lesson';
15449
15450                    break;
15451                default:
15452            }
15453
15454            $studentRemainingSecondsDelay = 0;
15455            $studentRemainingSecondsDelay = !empty($api['studentRemainingSecondsDelay']) ? $api['studentRemainingSecondsDelay'] : $studentRemainingSecondsDelay;
15456
15457            $showTakeBusinessTestModal = false;
15458            if (isset($user['User']['corporate_id'])) {
15459                $showTakeBusinessTestModal = false;
15460                $isTakenBusinessTestFlg = (isset($user['User']['monthly_speaking_business_attended_flg'])) ? $user['User']['monthly_speaking_business_attended_flg'] : 0;
15461                $isMustTakeBusinessTestFlg = (isset($user['User']['monthly_speaking_business_attended_must_flg'])) ? $user['User']['monthly_speaking_business_attended_must_flg'] : 0;
15462                $corporateUserDate = time();
15463                $twentyPlusDayOfTheMonth = strtotime(date('Y-m-20'));
15464
15465                if (
15466                    ($isTakenBusinessTestFlg == 0 && $isMustTakeBusinessTestFlg == 1) &&
15467                    !$isReserved &&
15468                    (
15469                        $corporateUserDate >= $twentyPlusDayOfTheMonth ||
15470                        (
15471                            $userAdminFlag == 1 ||
15472                            (
15473                                isset($user["User"]["nickname"]) &&
15474                                strpos(strtoupper($user["User"]["nickname"]), '%%%TEST%%%') !== false
15475                            )
15476                        )
15477                    )
15478                ) {
15479                    $showTakeBusinessTestModal = true;
15480                }
15481            }
15482
15483            // show orange button
15484            $lessonOrangeButtonRemaining = $this->triggerOrangeButton($studentId, $teacherId, $userNotEligible, $unsupportedBrowser, $canLesson['lessonAvailable']);
15485
15486            if (
15487                $canLessonTextbook &&             # - can lesson with the textbook
15488                !$textbookForReservationOnly && # - textbook not for reserve only
15489                !$unsupportedBrowser &&         # - supported browser
15490                $userDuplicateLesson &&         # - has lesson with other teacher
15491                !$this->isStudySapuriTosUser &&    # - not sapuri TOS user
15492                !in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')]) && 
15493                !in_array($user['User']['payment_plan_id'], Configure::read('payment_plan_lightplan'))  # - not lite plan user
15494            ) {
15495                $canMidwayLesson = true;
15496            }
15497        } else {
15498
15499        } //end $isGuestViewer
15500
15501        $isRedLamp = isset($data['redLamp']) && $data['redLamp'] == "1" ? true : false;
15502        $isRedLamp = (isset($teacherStatus['status']) && $teacherStatus['status'] == 5) ? true : $isRedLamp;
15503        $showLoader = $isGuestViewer ? true : false;    
15504        $suddenLessonFlg = false;
15505        $canDoLive = UserTable::canJoinLiveViewing($user['User']);        
15506
15507        if (
15508            $isReserved && 
15509            (
15510                $this->isStudySapuriUser || 
15511                $this->isStudySapuriTosUser || 
15512                in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')])
15513            )
15514        ) {
15515            $canDoLive = false;
15516        }
15517    
15518        if(
15519            !$isViewer && 
15520            !$isEmergencyLesson && 
15521            !$isReservedCanSuddenLesson & 
15522            !$canMidwayLesson &&
15523            !$isReserved
15524        ) {
15525            if($teacherStatusColor == 'wait') {
15526                if((!$canLessonTextbook && $this->isStudySapuriUser) || $membershipTypeReservationOnly) {
15527                    $isBusy = true;
15528                }
15529    
15530                if(!( !$canLessonTextbook && $this->isStudySapuriUser ) && !$membershipTypeReservationOnly) {
15531                    $suddenLessonFlg = true;
15532                }
15533            }
15534    
15535            if($teacherStatusColor == 'lesson' || $teacherStatusColor == 'offline') {
15536                if(!($unsupportedBrowser && $teacherStatusColor == 'lesson') || !$membershipTypeReservationOnly) {
15537                    
15538                    if($membershipTypeBlueBtn) {
15539                        $suddenLessonFlg = true;
15540                        $teacherStatusColor = 'wait';
15541                    }
15542                }
15543            }
15544        }
15545
15546        // set localize url
15547        if (
15548            isset($get['la']) && in_array($get['la'], array_flip(Configure::read('pc_allowed_currencies'))) &&
15549            $get['la'] != Configure::read('default.user_language')
15550        ) {
15551            $localizeUrl = myTools::getUrl() . '/' . $get['la'];
15552        } else {
15553            $localizeUrl = myTools::getUrl();
15554        }
15555
15556        $displayFamilyAlert = false;
15557        if (
15558            isset($this->sharedUserData['User']['parent_id']) &&
15559            !is_null($this->sharedUserData['User']['parent_id'])
15560        ) {
15561            $parent = $this->User->find('first', array(
15562                'fields' => array(
15563                    'User.id',
15564                    'User.hash16',
15565                    'User.charge_flg'
15566                ),
15567                'conditions' => array(
15568                    'User.id' => $this->sharedUserData['User']['parent_id']
15569                ),
15570                'recursive' => -1
15571            ));
15572
15573            if ($parent && $parent['User']['charge_flg'] != 1) {
15574                $displayFamilyAlert = true;
15575            }
15576        }
15577
15578        $device = false;
15579        if (strpos($ua, 'Silk') !== false) {
15580            $device = 'kindle';
15581        } else if (strpos($ua, 'Android') !== false) {
15582            $device = 'andriod';
15583        } else if (strpos($ua, 'iPhone') !== false) {
15584            $device = 'ios';
15585        } else if (strpos($ua, 'iPad') !== false) {
15586            $device = 'ios';
15587        } else if (strpos($ua, 'iPod') !== false) {
15588            $device = 'ios';
15589        } else {
15590            $device = 'pc';
15591        }
15592
15593        $liveLessonText = $liveData->lesson_flg ? __d('waiting','予約レッスン(LIVE)へ進む') : __d('waiting','予約レッスンへ進む');
15594        $button = $buttonStates[$stateButton];
15595        $canEmergencyLesson = false;
15596        $currentMinutes = date("i");
15597        $emergencyBreakTime = ['status' => false];
15598        $currentHour = date("H");
15599        
15600        if ($isEmergencyLesson) {
15601            if ($this->isStudySapuriTosUser) {
15602                $nextEmergencySlot = $this->LessonSchedule->getEmergencyTimeSlot();
15603                $nextReserveSlot = $this->LessonSchedule->getNextReservationTimeSlot();
15604                $queryCondition['fields'][] = "(
15605                    ((select smb.id from shift_work_meal_breaks as smb where smb.lesson_time >= '{$nextReserveSlot['start']}' and smb.lesson_time <= '{$nextReserveSlot['end']}' and smb.teacher_id = Teacher.id limit 1) IS NULL) AND 
15606                    ((Select rs.id from lesson_schedules as rs where rs.lesson_time >= '{$nextEmergencySlot['start']}' and rs.lesson_time <= '{$nextEmergencySlot['end']}' and rs.status = 1 and rs.teacher_id = Teacher.id limit 1) IS NULL)
15607                    ) as can_emergency_lesson";
15608                $queryCondition['fields'][] = "((Select rs.id from lesson_schedules as rs where rs.lesson_time >= '{$nextReserveSlot['start']}' and rs.lesson_time <= '{$nextReserveSlot['end']}' and rs.status = 1 and rs.user_id = {$studentId} limit 1) IS NULL) 
15609                    as student_no_next_reservation";
15610            }
15611
15612            $commonTeacherStatusParams = array(
15613                'page_display' => 'listTeacher',
15614                'query_conditions' => $queryCondition
15615            );
15616            $emergencyLessonOnair = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
15617            
15618            if (
15619                $this->isStudySapuriTosUser &&
15620                !$isReserved &&
15621                isset($emergencyLessonOnair[0]['can_emergency_lesson']) && 
15622                isset($emergencyLessonOnair[0]['student_no_next_reservation']) && 
15623                $emergencyLessonOnair[0]['can_emergency_lesson'] && # -can emergency
15624                $emergencyLessonOnair[0]['student_no_next_reservation']    # - no next reservation
15625            ) {
15626                $canEmergencyLesson = true;
15627            }
15628
15629            # ~if emergency lesson break time
15630            if ( !$isReserved && (($currentMinutes >= 26 && $currentMinutes <= 29) || ($currentMinutes >= 56 && $currentMinutes <= 59))) {
15631                $canEmergencyLesson = false;
15632                $emergencyBreakTime['status'] = true;
15633                $emergencyBreakTime['time_span'] = '['.$currentHour.'時26分 ~ '.$currentHour.'時30分]['.$currentHour.'時56分 ~ '.$currentHour.'時00分]';
15634                $emergencyBreakTime['time_return'] = '['.$currentHour.'時30分]['.$currentHour.'時00分]';
15635            }
15636        }        
15637
15638
15639        $isAvatar = $api['CommonTeacherStatus']['Teacher']['avatar_flg'] == 1 || $api['CommonTeacherStatus']['Teacher']['avatar_parent_flg'] == 1 ? true : false;
15640
15641        // lesson alert
15642        $lessonAlertMsg = [];
15643        $lessonAlertStatus = '';
15644
15645        // if emergency lesson break time
15646        if ($isEmergencyLesson && $emergencyBreakTime['status']) {
15647            $lessonAlertMsg = [
15648                ['text' => __d('waiting','しばらくお待ちください。')],
15649                ['text' => sprintf(__d('waiting','%sの間は緊急時予約レッスンにご入室いただけません。'), $emergencyBreakTime['time_span'])],
15650                ['text' => sprintf(__d('waiting','%sまでお待ちください。'), $emergencyBreakTime['time_return'])]
15651            ];
15652            $lessonAlertStatus = 'emergency_lesson_break_time';
15653        }
15654
15655        if (
15656            (isset($exceedDailyLimit) && $exceedDailyLimit) &&
15657            !$isReserved &&
15658            !$isAvatar
15659        ) {
15660            $lessonAlertMsg = [
15661                ['text' => __d('waiting','同一講師との連続した今すぐレッスンはレッスン完了から60分空けて再度受講が可能となります (講師の独占を緩和するため) 。')],
15662                ['text' => __d('waiting','※異なる講師を選択した場合は何度でも連続で今すぐレッスンの受講が可能です (今すぐレッスン回数無制限) 。')],
15663                ['text' => __d('waiting','※回線不具合等で短時間レッスンとなった場合は、レッスン合計時間が25分に達するまでの間は同一講師と連続で今すぐレッスンの受講が可能です。')]
15664            ];
15665            $lessonAlertStatus = 'exceed_daily_limit';
15666        }
15667
15668        $schedStartTime = isset($canLesson['nextReservation']['lesson_time']) ? TimezoneTable::computeTimeToUser(array('time' => strtotime($canLesson['nextReservation']['lesson_time']), 'timestamp' => $this->timeDiffSecond, 'format' => 'H:i')) : '';
15669        $schedEndTime = isset($canLesson['possibleTime']) ? TimezoneTable::computeTimeToUser(array('time' => strtotime($canLesson['possibleTime']), 'timestamp' => $this->timeDiffSecond, 'format' => 'H:i')) : '';
15670
15671        if(
15672            isset($canLesson['possibleTime']) &&
15673            $canLesson['possibleTime'] !== false &&
15674            (!isset($isAvatar) || $isAvatar == false) &&
15675            $studentId &&
15676            !(isset($exceedDailyLimit) && $exceedDailyLimit) &&
15677            !$isEmergencyLesson
15678        ) {
15679            $canReserveLessonForReserved = 1;
15680        } else {
15681            $canReserveLessonForReserved = 0;
15682        }
15683
15684        if(
15685            isset($canLesson['possibleTime']) &&
15686            $canLesson['possibleTime'] !== false &&
15687            $isAvatar == false &&
15688            $studentId &&
15689            !(isset($exceedDailyLimit) && $exceedDailyLimit) &&
15690            !$this->isStudySapuriTosUser && !$isEmergencyLesson # ~don't show in emergency page
15691        ) {
15692            $lessonAlertStatus == 'lesson_reservation';
15693            $lessonAlertMsg = ['text' => sprintf(__d('waiting','この講師は、%1$s から予約が入っているため、%2$s までのレッスンとなります。ご了承の上レッスンへお進みください。'), $schedStartTime, $schedEndTime)];
15694        }
15695
15696        // user has reserved class (attempts to have a lesson with another teacher)
15697        if (
15698            $isAvatar == false && 
15699            $reservedLessonData && 
15700            (!$canLesson['lessonAvailable']) && !empty($teacherStatus) && ($teacherStatus->status == 1) && 
15701            (!empty($teacherStatus) && isset($teacherStatus->connect_flg) && $teacherStatus->connect_flg == 1 ) && 
15702            !$isReservedCanSuddenLesson
15703        ) {
15704            $lessonAlertStatus = 'reserved_class';
15705        }
15706
15707        $corporateIndividualUser = false;
15708        $corporateTypes = Configure::read('corporate_type_arr');
15709        $corporateTypeUserTable = myTools::getCoporateTypeUsingPaymentPlanId($user['User']['payment_plan_id']);
15710        if (isset($user['User']['corporate_id'])) {
15711            $corporateAdminPaymentMethod = $this->Corporate->getPaymentMethod($user['User']['corporate_id']);
15712            $corporateIndividualUser = $corporateAdminPaymentMethod == 1 ? true : false;
15713        }
15714
15715        if (
15716            !$this->isStudySapuriUser &&
15717            $lessonType == Configure::read('lesson.type.reservation') &&
15718            ($uOnair && $uOnair['leave_lesson']) # - already left the reserved lesson
15719        ) {
15720            $isReservedCanLessonViewing = true;
15721        }
15722
15723        if(!$isGuestViewer) {
15724            $json = array_merge($json, [
15725                'apiStateButton' => $api['teacher']['state_button'],
15726                'button' => $button,
15727                'canDoLive' => $canDoLive,
15728                'canEmergencyLesson' => $canEmergencyLesson,
15729                'canLesson' => $canLesson,
15730                'canLessonTextbook' => $canLessonTextbook,
15731                'canMidwayLesson' => $canMidwayLesson,
15732                'canReserveLessonForReserved' => $canReserveLessonForReserved,
15733                'checkBadge' => $checkBadge,
15734                'corporateIndividualUser' => $corporateIndividualUser,
15735                'corporatePlanName' => isset($corporateTypeUserTable) ? (isset($corporateTypes[$corporateTypeUserTable]) ? $corporateTypes[$corporateTypeUserTable] : '') : '',
15736                'corporateType' => $corporateType,
15737                'corporateUserFlg' => $corporateUserFlg,
15738                'corpLightCondition' => $corpLightCondition1,
15739                'counselingFlg' => $counselingFlg,
15740                'device' => $device,
15741                'displayFamilyAlert' => $displayFamilyAlert,
15742                'dummyLessonRoom' => $hasLessonBeforeActualTime,
15743                'emergencyBreakTime' => $emergencyBreakTime,
15744                'exceedDailyLimit' => isset($exceedDailyLimit) ? $exceedDailyLimit : false,
15745                'hasLessonBeforeActualTime' => $hasLessonBeforeActualTime,
15746                'hasRemainingLife' => $hasRemainingLife,
15747                'homeFlg' => $api['CommonTeacherStatus']['Teacher']['home_flg'],
15748                'isAvatar' => $isAvatar,
15749                'isBusy' => $isBusy,
15750                'isEmergencyLesson' => $isEmergencyLesson,
15751                'isNormalLitePlanUser' => $isNormalLitePlanUser,
15752                'isRedLamp' => $isRedLamp,
15753                'isReserved' => $isReserved,
15754                'isReservedCanLessonViewing' => $isReservedCanLessonViewing,
15755                'isReservedCanSuddenLesson' => $isReservedCanSuddenLesson,
15756                'isStudySapuriTosUser' => $this->isStudySapuriUser,
15757                'isViewer' => $isViewer,
15758                'lessonAlertMsg' => $lessonAlertMsg,
15759                'lessonAlertStatus' => $lessonAlertStatus,
15760                'lessonOnAir' => $teacherStatusOnAir,
15761                'lessonOnOther' => $lessonOnOther,
15762                'lessonOrangeButtonRemaining' => $lessonOrangeButtonRemaining,
15763                'lessonType' => $lessonType,
15764                'liveData' => $liveData,
15765                'liveLessonFlg' => $liveLessonFlg ?? null,
15766                'liveLessonText' => $liveLessonText,
15767                'liveStatus' => $liveStatus,
15768                'localizeUrl' => $localizeUrl,
15769                'membershipTypeBlueBtn' => $membershipTypeBlueBtn,
15770                'membershipTypeReservationOnly' => $membershipTypeReservationOnly,
15771                'onair' => $onair,
15772                'uOnair' => $uOnair,
15773                'onGoingLesson' => $onGoingLesson,
15774                'ownReservationFlg' => $ownReservationFlg,
15775                'paymentPlanId' => $user['User']['payment_plan_id'],
15776                'points' => $this->UsersPoint->getCurrentUserPoint($studentId),
15777                'redirectPlanUrl' => $redirectPlanUrl,
15778                'remainingLessonTime' => (int) $remainingLessonTime,
15779                'reservedLessonData' => $reservedLessonData,
15780                'sapuriCoin' => $sapuriCoin,
15781                'scheduleReservationData' => $scheduleReservationData,
15782                'schedEndTime' => $schedEndTime,
15783                'schedStartTime' => $schedStartTime,
15784                'showLoader' => $showLoader,
15785                'showNativeSpeakerWarning' => $showNativeSpeakerWarning,
15786                'showTakeBusinessTestModal' => $showTakeBusinessTestModal,
15787                'stateButton' => $stateButton,
15788                'studentId' => $studentId,
15789                'suddenLessonFlg' => $suddenLessonFlg,
15790                'teacherAvatarFlg' => $api['CommonTeacherStatus']['Teacher']['avatar_flg'] == 1 ? true : false,
15791                'teacherLeaveNotice' => $teacherLeaveNotice,
15792                'teacherStatus' => $teacherStatus,
15793                'teacherStatusApi' => $_teacherStatus,
15794                'teacherStatusColor' => $teacherStatusColor,
15795                'textbookForReservationOnly' => (int)$textbookForReservationOnly,
15796                'unverifiedSMS' => $stateButton == 7 ? true : false,
15797                'unsupportedBrowser' => $unsupportedBrowser,
15798                'use7DaysTrialModal' => $use7DaysTrialModal,
15799                'userAdminFlag' => $userAdminFlag,
15800                'userDoubleCheckFlag' => $userDoubleCheckFlag,
15801                'userDuplicateLesson' => $userDuplicateLesson,
15802                'userFailFlag' => $userFailFlag,
15803                'userMembershipType' => $this->userMembershipType,
15804                'userNativeOption' => $user['User']['native_option'],
15805                'userNotEligible' => $userNotEligible
15806            ]);
15807
15808            if($membershipTypeReservationOnly) {
15809                $json['lessonStartBtnText'] = __d('waiting','予約専用です');
15810            }
15811
15812            if(
15813                $remainingLessonTime > 0 && 
15814                $remainingLessonTime < 660 &&
15815                !empty($teacherStatusOnAir['user_id']) && $teacherStatusOnAir['user_id'] != $studentId
15816            ) {
15817                $json['remainingLessonEndTime'] = $oOnair['end_time'];
15818
15819                if($remainingLessonTime <= 60) {
15820                    $json['lessonStartBtnText'] = __d('waiting', 'レッスン終了まで もうすぐ');
15821                } else {
15822                    $json['lessonStartBtnText'] = __d('waiting', 'レッスン終了まで あと%s分');
15823                }
15824            }
15825
15826            if($suddenLessonFlg) {
15827                if($use7DaysTrialModal) {
15828                    $json['suddenLessonStatus'] = 'use7DaysTrialModal';
15829                } else if (!empty(trim($redirectPlanUrl))) {
15830                    $json['suddenLessonStatus'] = 'redirectPlanUrl';
15831                } else if ($showNativeSpeakerWarning) {
15832                    $json['suddenLessonStatus'] = 'showNativeSpeakerWarning';
15833                } else if ($unsupportedBrowser) {
15834                    $json['suddenLessonStatus'] = 'unsupportedBrowser';
15835                } else if (!$canLessonTextbook) {
15836                    $json['suddenLessonStatus'] = 'cannotLessonTextbook';
15837                } else if (!empty($teacherLeaveNotice)) {
15838                    $json['suddenLessonStatus'] = 'teacherLeaveNotice';    
15839                }
15840
15841                if(!empty($json['suddenLessonStatus'])) {
15842                    $json['validateSuddenLessonFlg'] = false;
15843                } else {
15844                    $json['validateSuddenLessonFlg'] = true;
15845                }
15846            }
15847
15848        } else if ($isGuestViewer || $isViewer) {
15849            $json = array_merge($json, [
15850                'canLesson' => $canLesson,
15851                'isViewer' => $isViewer,
15852            ]);
15853        }
15854
15855        if($env != 'PRODUCTION') {
15856            $json['api'] = $api;
15857            $json['commonTeacher2'] = $commonTeacher2;
15858            $json['emergencyLessonOnair'] = $emergencyLessonOnair;
15859            $json['teacherStudentConnection'] = $api['teacherStudentConnection'];
15860            $json['tmpLessonOnAir'] = $tmp;
15861            $json['nextEmergencySlot'] = $nextEmergencySlot;
15862            $json['nextReserveSlot'] = $nextReserveSlot;
15863        }
15864
15865        return json_encode($json);
15866    }
15867
15868    public function checkLessonStartButtonAvatar() {
15869        $this->autoRender = false;
15870        $this->layout = false;
15871        $user = $this->sharedUserData;
15872        $data = $this->request->data;
15873        $response = [];
15874        $ua = myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']) ?? '';
15875        $env = Configure::read('ENVIRONMENT');
15876    
15877        if(empty($data['teacherId'])) {
15878            $response['error'] = 'Invalid parameters!';
15879            return json_encode($response);
15880        }
15881    
15882        // if api token is not set
15883        if (empty($user['User']['api_token'])) {
15884            $userApiToken = $this->User->generateAndSaveApiToken($data['studentId']);
15885            $this->Session->write('Auth.User.api_token', $userApiToken);
15886        }
15887    
15888        $studentId = (int) $data['studentId'];
15889        $teacherId = (int) $data['teacherId'];
15890        $counselingFlg = $data['counselingFlg'] ?? 0;
15891        myTools::initializeApiTunnel(array('TeachersDetailController'));
15892        $TeachersDetailController = new TeachersDetailController();
15893        $TeachersDetailController->params = [
15894            'nc_terminal_type' => 1, // pc
15895            'users_api_token' => $user['User']['api_token'],
15896            'teachers_id' => (int) $data['teacherId'],
15897            'la' => $data['la']
15898        ];    
15899        $api = json_decode($TeachersDetailController->detail(), true);
15900
15901        if (json_last_error() !== JSON_ERROR_NONE) {
15902            $response['error'] = 'Failed to decode API response.';
15903            return json_encode($response);
15904        }
15905
15906        $isGuestViewer = empty($studentId) ? 1 : 0;
15907        $lessonStartBtnText = __d('waiting','今すぐレッスンへ進む');
15908        $lessonStartBtnTextBusy = __d('waiting','取り込み中');
15909        $lessonOrangeButtonRemaining = false;
15910        $loginDialog = [
15911            'headerMessage' => __d('login', 'ログインが必要です'),
15912            'message' => __d('login', 'こちらの機能は、ログイン後にご利用いただけます.'),
15913            'loginBtn' =>  __d('login', 'ログインはこちら'),
15914            'registerBtn' => __d('login', '新規会員登録はこちら')
15915        ];
15916        $json = [
15917            'lessonStartBtnText' => $lessonStartBtnText,
15918            'lessonStartBtnTextBusy' => $lessonStartBtnTextBusy,
15919            'isGuestViewer' => (bool) $isGuestViewer,
15920            'loginDialog' => $loginDialog,
15921            'fullBaseUrl' => $this->baseUrl,
15922        ];
15923        $canLessonParam = array(
15924            'homeFlag' => isset($api['teacher']['home_flg']) ? $api['teacher']['home_flg'] : null,
15925            'isGuestViwer' => $isGuestViewer
15926        );
15927        $canMidwayLesson = false;
15928        $canLesson = LessonOnairTable::canLesson($teacherId, $studentId, $canLessonParam);    
15929        $liveDefault = (object)[
15930            'max_viewer' => Configure::read('max_live_lesson_viewer'),
15931            'lesson_flg' => 0,
15932            'lesson_joined' => 0,
15933            'lesson_started' => 0,
15934            'lesson_finish' => 0
15935        ];
15936        $liveData = isset($canLesson['liveLessonDetail']) && !empty($canLesson['liveLessonDetail']) ? $canLesson['liveLessonDetail'] : $liveDefault;
15937        $currentMin = date('i');
15938        $isViewer = 0;
15939        $onair = $api['LessonOnair'];
15940        $hasRemainingLife = false;
15941        $unsupportedBrowser = false;
15942        $browser =  $this->request->header('User-Agent');
15943
15944        if (preg_match('/(Edg|Edge)/i',$browser) ) {
15945            $unsupportedBrowser = false;
15946        } elseif (preg_match('/(OPR)/i',$browser)) {
15947            $unsupportedBrowser = true;
15948        } elseif (preg_match('/(Chrome|Firefox|Safari)/i',$browser)) {
15949            $unsupportedBrowser = false;
15950        } else {
15951            $unsupportedBrowser = true;
15952        }
15953
15954        if (($currentMin >= 25 && $currentMin < 30) || ($currentMin >= 55 && $currentMin <= 59)) {
15955            $reservedId = isset($canLesson['nextReservation']['user_id']) ? $canLesson['nextReservation']['user_id'] : null;
15956        } else {
15957            $reservedId = isset($canLesson['currentReservation']['user_id']) ? $canLesson['currentReservation']['user_id'] : null;
15958        }
15959
15960        if(
15961            $liveData->lesson_flg && 
15962            (
15963                (
15964                    !is_null($onair['user_id']) &&
15965                    $onair['user_id'] == $studentId
15966                )
15967                ||
15968                (
15969                    is_null($onair['user_id']) &&
15970                    $reservedId &&
15971                    $reservedId != $studentId
15972                )
15973            )
15974        ) {
15975            $isViewer = 1;
15976        }
15977
15978        $isGuestViewer = (empty($studentId) && $isViewer) ? 1 : 0;
15979    
15980        if(!$isGuestViewer) {
15981            if(!empty($api['error'])) {
15982                $json['api_error'] = $api['error'];
15983                return json_encode($json);
15984            }
15985    
15986            $buttonStates = array_flip(Configure::read('user_detail_state_button'));
15987            $stateButton = $api['teacher']['state_button'];
15988            $teacherStatusOnAir = $api['LessonOnair'] ?? null;
15989            $_teacherStatus = $api['TeacherStatus'];
15990            $reservedLessonData = $api['reservedLessonData'];
15991            $isReserved = $api['isReserved'];
15992            $teacher = $api['CommonTeacher`Status']['Teacher'];
15993            $checkBadge = $api['checkBadge'];
15994            $teacherStatus = !empty($_teacherStatus) && empty($teacherStatusOnAir) ? $_teacherStatus : $teacherStatusOnAir;
15995            $_paymentPlanID = isset($user['User']['payment_plan_id']) ? $user['User']['payment_plan_id'] : null;
15996            $isNormalLitePlanUser = (in_array($_paymentPlanID, Configure::read('lite_payment_plans') ) ) ? true : false;
15997            $stateButtonAddntlCheck = Configure::read('user_detail_state_button_addntl_check');
15998            $userNotEligible = false;
15999            $lessonType = false;
16000            $lessonOnOther = false;
16001            $lessonStartBtnText = $isNormalLitePlanUser ? __d('waiting','予約専用です') : __d('waiting','今すぐレッスンへ進む');
16002            $userDuplicateLesson = false;
16003            $isReservedCanSuddenLesson = false;
16004            $isReservedCanLessonViewing = false;
16005            $userAdminFlag = isset($user['User']['admin_flg']) ? $user['User']['admin_flg'] : '';
16006            $userFailFlag = isset($user['User']['fail_flg']) ? $user['User']['fail_flg'] : '';
16007            $userDoubleCheckFlag = isset($user['User']['double_check_flg']) ? $user['User']['double_check_flg']: '';
16008            $userCardCompany = isset($user['User']['card_company']) ? $user['User']['card_company']: '';
16009            $corporateUserFlg = isset($user['User']['corporate_id']) ? $user['User']['corporate_id'] : false;
16010            $isEmergencyLesson = (isset($data['emergencyFlg']) && $data['emergencyFlg']) ? true : false;
16011            $hasLessonBeforeActualTime = false;
16012            $teacherStatusColor = '';
16013            $ownReservationFlg = 0;
16014            $liveStatus = 0;
16015            $isBusy = false;
16016            $use7DaysTrialModal = false;
16017            $redirectPlanUrl = '';
16018            $teacherLeaveNotice = '';
16019            $showNativeSpeakerWarning = false;
16020            $baseUrl = myTools::getUrl($this->localizeDir);                
16021            
16022            // get reservation
16023            $nextReservation = LessonScheduleTable::getReservation(array(
16024                'LessonSchedule.teacher_id' => $api['CommonTeacherStatus']['Teacher']['id'],
16025                'LessonSchedule.user_id' => $data['studentId']
16026            ));
16027
16028            $this->Teacher->unbindModel(array('hasOne' => array('LessonOnair')));
16029            $queryCondition = array(
16030                'fields' => array(
16031                        'TeacherRankCoin.coins',
16032                        'TeacherRankCoin.reserve_coin_settings_flg',
16033                        'LessonOnair.id',
16034                        'LessonOnair.teacher_id',
16035                        'LessonOnair.user_id',
16036                        'TeacherRankCoin.limited_plan_reservation'
16037                    ),
16038                'joins' => array(
16039                    array(
16040                        'type' => 'LEFT',
16041                        'table' => 'teacher_rank_coins',
16042                        'alias' => 'TeacherRankCoin',
16043                        'conditions' => array('Teacher.rank_coin_id = TeacherRankCoin.id AND TeacherRankCoin.status')
16044                    )
16045                ),
16046                'conditions' => array(
16047                    array('Teacher.id' => $teacherId)
16048                ),
16049                'show' => 'first'
16050            );
16051
16052            $commonTeacherStatusParams = array(
16053                'page_display' => 'listTeacher',
16054                'query_conditions' => $queryCondition
16055            );
16056
16057            $commonTeacher2 = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
16058            $loStatusParams = array(
16059                'LessonOnair' => $commonTeacher2['LessonOnair'],
16060                'Teacher' => $api['CommonTeacherStatus']['Teacher'],
16061                'TeacherStatus' => $api['CommonTeacherStatus']['TeacherStatus'],
16062                'nextReservation' => isset($nextReservation['teacher_id']) ? $nextReservation['teacher_id'] : null,
16063                'userId' => $studentId
16064            );
16065            $teacherStatusNew = LessonOnairTable::teacherStatusColor($loStatusParams);
16066            $teacherParams = array(
16067                    'type' => 'first',
16068                    'args' => array(
16069                        'conditions' => array(
16070                            'id' => $teacherId
16071                        ),
16072                        'recursive' => -1
16073                    )
16074                );
16075            $teacherInfo = $this->Teacher->getTeachers($teacherParams);
16076
16077            if (
16078                ($teacher['avatar_id'] &&
16079                $teacherStatus['status'] == 4)
16080            ) {
16081                $teacherStatusNew = 3;
16082            }
16083
16084            if(empty($reservedLessonData)) {
16085                $this->LessonSchedule->recursive = 0;
16086                $reservedLessonData = $this->LessonSchedule->getReservationLessonNow($studentId);
16087            }
16088
16089            $teacherStatusColor = TeacherTable::teacherStatusCSS($teacherStatusNew);
16090            $sapuriCoin = $api['teacher']['sapuri_coin'];
16091    
16092            // additional state button check from callLessonAlertandStartButton
16093            if(in_array($stateButton, $stateButtonAddntlCheck)) {
16094                // check if lessonOnair is empty
16095                if (isset($api['CommonTeacherStatus']['LessonOnair'])) {
16096                    $tmp = (object) $api['CommonTeacherStatus']['LessonOnair'];
16097                    if (!$tmp->id) {
16098                        $api['CommonTeacherStatus']['LessonOnair'] = null;
16099                    }
16100                }
16101    
16102                // check if lessonOnair contains empty values
16103                $oOnair = !empty($teacherStatus1) && empty($onair) 
16104                            ? new TeacherStatusTable($teacherStatus1)
16105                            : $onair;
16106    
16107                //get next available schedule
16108                $checkNextSchedule = null;
16109                $checkScheduleCurrent = null;
16110                $lesson_time_stamp = floor(time() / (30 * 60)) * (30 * 60);
16111    
16112                if(isset($canLesson['nextReserve'])) {
16113                    $nextSchedule = isset($canLesson['nextReserve']['start']) ? $canLesson['nextReserve']['start'] : null;
16114                    $checkNextSchedule = $nextSchedule ? $this->ShiftWorkOn->checkDataExist($teacherId , $nextSchedule) : null;
16115                    $checkScheduleCurrent = $this->ShiftWorkOn->checkDataExist( $teacherId , date('Y-m-d H:i:s',$lesson_time_stamp));
16116                }
16117    
16118                $checkNextSchedule = !empty($checkNextSchedule) ? $checkNextSchedule : false;
16119                $checkScheduleCurrent = !empty($checkScheduleCurrent) ? $checkScheduleCurrent : false;
16120                $nextSchedule = isset($nextSchedule) ? $nextSchedule : '';
16121    
16122                // add trappings for meal break, and change $canLesson['nextReserve']['start'] to mealbreak slot if has mealbreak
16123                if (
16124                    (($canLesson['lessonAvailable']
16125                    && !$checkNextSchedule 
16126                    && $checkScheduleCurrent)
16127                    || (isset($canLesson['hasMealbreakNext']) && $canLesson['hasMealbreakNext']))
16128                    && !($teacherInfo['Teacher']['avatar_parent_flg'] == 1 || $teacherInfo['Teacher']['avatar_flg'] == 1)
16129                    && !$isEmergencyLesson  # ~don't show in emergency page
16130                    && !$this->isStudySapuriTosUser
16131                    && $teacherInfo['Teacher']['home_flg'] != 1 // not home based teacher
16132                    && isset($exceedDailyLimit) && !empty($exceedDailyLimit) 
16133                ) {
16134                    $teacherLeaveNotice .= __d('waiting','こちらの講師は'). " ";
16135                    $teacherLeaveNotice .= isset($nextSchedule) ? TimezoneTable::computeTimeToUser(array('time' => strtotime($canLesson['nextReserve']['start']), 'timestamp' => $this->timeDiffSecond, 'format' => 'h:i')) : '';
16136                    $teacherLeaveNotice .= " ". __d('waiting','までのレッスンとなりますので<br>ご了承ください。');
16137                }
16138    
16139                // NJ-29831: check if user has reserved lesson for the next 5 min
16140                $scheduleReservationData = $this->LessonSchedule->getScheduledReservationNow($studentId, $teacherInfo['Teacher']['id']);
16141                $onGoingLesson = $this->LessonOnair->hasOngoingLesson($this->Auth->user('id'));
16142                $hasLessonBeforeActualTime = false;
16143    
16144                if (!empty($scheduleReservationData) && !$onGoingLesson) {
16145                    $hasLessonBeforeActualTime = true;
16146                    $isReserved = true;
16147                }
16148    
16149                //get preset textbook or last viewed
16150                $presetParams = array("user_id" => $studentId, 'userValidForSSBEDT' => $this->userValidForSSBEDT());
16151    
16152                //add additional parameter in fetching preset textbook
16153                if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))) {
16154                    $presetParams["lang"] = $this->localizeDir;
16155                }
16156    
16157                $preset_data = $this->UsersTextbookInfo->getPreset($presetParams);
16158                if(isset($preset_data['preset_connect_id']) && !empty($preset_data['preset_connect_id'])) {
16159                    # for preset
16160                    $presetParams['connect_id'] = $preset_data['preset_connect_id'];
16161                    $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
16162    
16163                } else if(isset($preset_data['last_viewed_connect_id']) && !empty($preset_data['last_viewed_connect_id'])) {
16164                    # use last viewed textbook if no preset data.
16165                    $presetParams['connect_id'] = $preset_data['last_viewed_connect_id'];
16166                    $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
16167                }
16168    
16169                // - NJ-3878 : add trapping for pc and app(api) 1 = pc 0 = app
16170                $presetParams['is_pc_flg'] = 1;
16171    
16172                # fetch preset
16173                $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
16174                if(!$preset) {
16175                    unset($presetParams['connect_id']);
16176                    unset($presetParams['last_opened_date']);
16177                    $preset = $this->UsersTextbookInfo->getTextbookInfos($presetParams);
16178                }
16179    
16180                $lessonData = $preset["textbook_info"];
16181                $categoryId = $lessonData["TextbookCategory"]["id"];
16182                $categoryTypeId = $lessonData["TextbookCategory"]["type_id"];
16183                $textbookId = $lessonData["Textbook"]["id"];
16184                
16185                if( $categoryTypeId == 1 ) { // course
16186                    $seriesId = $this->Textbook->getTextbookSeriesId(array( 'textbook_id' => $textbookId ));
16187                } else { // series
16188                    $seriesId = $categoryId;
16189                }
16190
16191                if(empty($checkBadge)) {
16192                    $checkBadge = $this->TeacherBadge->find("first", array(
16193                        "conditions" => array(
16194                            "TeacherBadge.teacher_id" => $teacherId,
16195                            "TeacherBadge.textbook_category_id" => $seriesId
16196                        ),
16197                        "fields" => array("TeacherBadge.id"),
16198                        "recursive" => -1
16199                    ));
16200                }
16201    
16202                $canLessonTextbook = $checkBadge || $counselingFlg ? true : false;                
16203    
16204                //check if the preset textbook is doesn't have reserve_flg
16205                $textbookForReservationOnly = isset($preset['reservation_flg']) ? $preset['reservation_flg'] : false;
16206                $uOnair = isset($onGoingLesson['LessonOnair']) ? $onGoingLesson['LessonOnair']: '';
16207                
16208                $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($user['User']['payment_plan_id']);
16209    
16210                if ($uOnair != null) {
16211                    $uOOnair = new LessonOnairTable($uOnair);
16212                    //check user duplicate lesson
16213                    if ($uOOnair && $uOOnair->status == 3 && $uOOnair->user_id == $this->Auth->User('id') && $uOOnair->teacher_id != $teacherId) {
16214                        $userDuplicateLesson = true;
16215                        $lessonType = $uOOnair->lesson_type;
16216                    }
16217                    //check lesson on others
16218                    if ($oOnair && $oOnair->status == 3 && $oOnair->teacher_id == $teacherId && $oOnair->user_id != $studentId) {
16219                        $lessonOnOther = true;
16220                    }
16221                }
16222    
16223                # - [NJ-18003] conditions for terminate reserved lesson for sudden lesson
16224                if (
16225                    $canLessonTextbook &&             # - can lesson with the textbook
16226                    !$textbookForReservationOnly && # - textbook not for reserve only
16227                    !$unsupportedBrowser &&         # - supported browser
16228                    $userDuplicateLesson &&         # - has lesson with other teacher
16229                    $lessonType == Configure::read('lesson.type.reservation') &&
16230                    !$this->isStudySapuriTosUser &&    # - not sapuri TOS user
16231                    !$this->isStudySapuriUser &&    # - not sapuri user
16232                    ($uOnair && $uOnair['leave_lesson']) && # - already left the reserved lesson
16233                    !in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')]) && 
16234                    !in_array($user['User']['payment_plan_id'], Configure::read('payment_plan_lightplan'))  # - not lite plan user
16235                ) {
16236                    $isReservedCanSuddenLesson = true;
16237                }
16238    
16239                // if failed settlement -> paid or corporate individual (standard/premium)
16240                if (in_array($this->userMembershipType, Configure::read('membership_type_credit_retry'))) {
16241                    $redirectPlanUrl = $baseUrl . '/payment/payment_credit_retry';
16242                // if free 
16243                } elseif ($this->userMembershipType == Configure::read('membership_type_plan_free')) {
16244                    $redirectPlanUrl = $baseUrl . '/payment/payment_credit_charge';
16245                // if free (trial not yet conducted)
16246                } elseif ($this->userMembershipType == 13) {
16247                    $userNotEligible = 10;
16248                    $use7DaysTrialModal = true;
16249                // if corporate company settlement failed -> standard/premium or
16250                } elseif (in_array($this->userMembershipType, Configure::read('membership_type_corporate_company_failed'))) {
16251                    $redirectPlanUrl = $baseUrl . '/account/contract_information';
16252                }
16253
16254                // NJ-48797
16255                $avatarParentFlg = isset($commonTeacher2['Teacher']['avatar_parent_flg']) && $commonTeacher2['Teacher']['avatar_parent_flg'] == 1;
16256
16257                if (!$avatarParentFlg) {
16258                    $getParentAvatarTeacher = $this->Teacher->find('first', array(
16259                        'fields' => array('Teacher.id', 'Teacher.native_speaker_flg'),
16260                        'conditions' => array(
16261                            'Teacher.id' => $commonTeacher2['Teacher']['avatar_id'],
16262                            'Teacher.avatar_parent_flg' => 1
16263                        ),
16264                        'recursive' => -1
16265                    ));
16266                } else {
16267                    $getParentAvatarTeacher = $commonTeacher2;
16268                }
16269                
16270                $membershipTypeReservationOnlyArr = Configure::read('membership_type_blue_btn_reservation_only');
16271                $membershipTypeReservationOnly = false;
16272    
16273                if(in_array($this->userMembershipType, $membershipTypeReservationOnlyArr)) {
16274                    $membershipTypeReservationOnly = true;
16275                }
16276    
16277                $membershipTypeBlueBtnArr = Configure::read('membership_type_blue_btn');
16278                $membershipTypeBlueBtn = false;
16279    
16280                if(in_array($this->userMembershipType, $membershipTypeBlueBtnArr)) {
16281                    $teacherStatusColor = 'wait';
16282                    $membershipTypeBlueBtn = true;
16283                }
16284    
16285                $liveLessonFlg = isset($commonTeacher2['LessonOnair']['live_lesson_flg']) ? $commonTeacher2['LessonOnair']['live_lesson_flg'] : 0;
16286    
16287                if(!$isGuestViewer && $liveLessonFlg) {
16288                    $reservedLessonData = $api['reservedLessonData'];
16289    
16290                    if ($reservedLessonData && $reservedLessonData['Teacher']['id'] != $teacherId) {
16291                        $liveStatus = 0;
16292                    } else {
16293                        //- if lesson started
16294                        if (
16295                            !is_null($api['LessonOnair']['connect_id']) &&
16296                            !is_null($api['LessonOnair']['user_id'])
16297                        ) {
16298                            if ($api['LessonOnair']['user_id'] == $studentId) {
16299                                $liveStatus = 4;
16300                            } else {
16301                                //- check live status
16302                                $liveStatus = $this->LessonOnairsViewer->onGoingLiveStatus([
16303                                    'user_id' => $studentId,
16304                                    'chat_hash' => $api['LessonOnair']['chat_hash']
16305                                ]);
16306    
16307                                //-- override status to watch
16308                                if ($liveStatus == 1) {
16309                                    $liveStatus = 2; //view live
16310                                }
16311                            }
16312                        } else {
16313                            $waitingReservationLive = $this->LessonSchedule->getWaitingLiveReservation([
16314                                'teacher_id' => $teacherId
16315                            ]);
16316    
16317                            //-has reservation
16318                            if ($waitingReservationLive) {
16319                                if ($waitingReservationLive['LessonSchedule']['user_id'] == $studentId) {
16320                                    $liveStatus = (date('i') >= 0 && date('i') <= 26) || (date('i') >= 30 && date('i') <= 56) ? 4 : 0;
16321                                } else {
16322                                    $liveStatus = 1; //live will start
16323                                }
16324                            }
16325                        }
16326                    }
16327                }
16328    
16329                if(!$this->isStudySapuriTosUser) {
16330                    $teacherStudentConnection = $api['teacherStudentConnection'];        
16331                    $teacherStudentData = isset($teacherStudentConnection['TeacherStudentConnection']) ? $teacherStudentConnection['TeacherStudentConnection'] : array();
16332                    if (isset($teacherStudentData['daily_lesson_minutes']) && $teacherStudentData['daily_lesson_minutes']) {
16333                        $exceedDailyLimit = $this->LessonOnair->lessonStartButton(array(
16334                            'teacher_id' => $teacherId,
16335                            'teacherStudentData' => $teacherStudentData,
16336                            'counseling_flg' => isset($commonTeacher2['Teacher']['counseling_flg']) ? $commonTeacher2['Teacher']['counseling_flg'] : 0,
16337                            'avatar_flg' => isset($commonTeacher2['Teacher']['avatar_flg']) ? $commonTeacher2['Teacher']['avatar_flg'] : 0,
16338                            'nickname' => $user['User']['nickname'],
16339                            'admin_flg' => $userAdminFlag,
16340                            'isReserved' => $isReserved,
16341                            'type' => 1
16342                        ));
16343                    }
16344                }
16345    
16346                // check if busy
16347                if(isset($exceedDailyLimit) && $exceedDailyLimit && !$isReserved && !$liveData->lesson_flg && !$isGuestViewer) {
16348                    if(empty($teacherStatus->status) || (!empty($teacherStatus->status) && $teacherStatus->status == 1)) {
16349                        $isBusy = true;
16350                    }
16351                }
16352    
16353                // NC-5409 : Corporate Limited Plan
16354                if ( isset($corporateType) &&  $corporateType == Configure::read('corporate_type.limited') ) {
16355    
16356                    // check if legible
16357                    if (
16358                        (    ($corporateType == Configure::read('corporate_type.limited') && !$isReserved) ||
16359                            (!$isReserved && (!$canLessonTextbook || $textbookForReservationOnly)) ||
16360                            $userDuplicateLesson || 
16361                            $unsupportedBrowser ||
16362                            $lessonOnOther
16363                        ) &&
16364                        $studentId
16365                    ) {
16366                        $userNotEligible = 1;
16367                    }
16368    
16369                } elseif ( isset($corporateType) &&  $corporateType == Configure::read('corporate_type.light') ) {
16370    
16371                    $corpLightCondition1 = (
16372                        ($corporateType == Configure::read('corporate_type.light') && !$isReserved) ||
16373                        (!$isReserved && (!$canLessonTextbook || $textbookForReservationOnly)) ||
16374                        $userDuplicateLesson ||
16375                        $unsupportedBrowser ||
16376                        $lessonOnOther
16377                    );
16378                    // check if legible
16379                    if ( $corpLightCondition1 && $studentId) {
16380                        $userNotEligible = 2;
16381                    }
16382                } elseif (
16383                    (
16384                        isset($commonTeacher2['Teacher']['native_speaker_flg']) &&
16385                        $commonTeacher2['Teacher']['native_speaker_flg']
16386                    ) &&
16387                    (
16388                        $user['User']['native_option'] == null ||
16389                        $user['User']['native_option'] == 0
16390                    ) &&
16391                    !$isReserved &&
16392                    !$tmp->live_lesson_flg &&
16393                    !$this->isStudySapuriTosUser
16394                ) {
16395                    $userNotEligible = 3;
16396                    $showNativeSpeakerWarning = true;
16397                } elseif ( // NJ-48797
16398                    (isset($getParentAvatarTeacher['Teacher']['native_speaker_flg']) && $getParentAvatarTeacher['Teacher']['native_speaker_flg']) &&
16399                    ($user['User']['native_option'] == null || $user['User']['native_option'] == 0) && 
16400                    !$isReserved &&
16401                    !$tmp->live_lesson_flg &&
16402                    !$this->isStudySapuriTosUser
16403                ) {
16404                    $showNativeSpeakerWarning = true;
16405                    $userNotEligible = 4;
16406                } else {
16407                    // check if legible
16408                    if ((
16409                        (!$isReserved && (!$canLessonTextbook ||$textbookForReservationOnly)) ||
16410                        $userDuplicateLesson || 
16411                        $unsupportedBrowser || 
16412                        (!$userAdminFlag && ($userFailFlag == 1 || $userDoubleCheckFlag == 2)) ||
16413                        $lessonOnOther
16414                    ) && $studentId) {
16415                        $userNotEligible = 5;
16416                    }
16417                }
16418    
16419                # ~no sudden lesson for sapuri toS user
16420                if ($this->isStudySapuriTosUser && !$isReserved) {
16421                    $userNotEligible = 6;
16422                }
16423    
16424                $_userReservedNowLesson = ($reservedLessonData && $reservedLessonData['Teacher']['id'] == $teacherId) ? true : false;
16425    
16426                if (in_array($user['User']['payment_plan_id'],Configure::read('lite_payment_plans')) && !$_userReservedNowLesson && !$isEmergencyLesson) {
16427                    # disable the lesson button for lite plan if it is not reserved lesson
16428                    $userNotEligible = 7;
16429    
16430                    # add if reserve is still ongoing 
16431                    if($isReserved) {
16432                        $userNotEligible = false;
16433                    }
16434                }
16435    
16436            }            
16437    
16438            switch($stateButton) {
16439                case 2: //proceed_to_the_lesson_immediately
16440                    if (!empty($api['CommonTeacherStatus']['user_id']) &&
16441                        $api['CommonTeacherStatus']['user_id'] != $user['id'] &&
16442                        in_array($api['CommonTeacherStatus']['TeacherStatus']['status'], [1, 3])
16443                    ) {
16444                        $stateButton = 5; //busy
16445                    }
16446                    break;
16447                case 3: // go to reserved lesson
16448                case 32: // dummy lesson
16449                    $teacherStatusColor = 'wait';
16450                    break;
16451                case 15: //other
16452                case 5: //busy
16453                    if(
16454                        ($teacherStatusColor == 'lesson' || $teacherStatusColor == 'offline') &&
16455                        $membershipTypeReservationOnly
16456                    ) {
16457                        $stateButton = 6;
16458                        $lessonStartBtnText = __d('waiting','予約専用です');
16459                    }
16460                    $teacherStatusColor = 'lesson';
16461    
16462                    break;
16463                default:
16464            }
16465
16466            $studentRemainingSecondsDelay = 0;
16467            $studentRemainingSecondsDelay = !empty($api['studentRemainingSecondsDelay']) ? $api['studentRemainingSecondsDelay'] : $studentRemainingSecondsDelay;
16468    
16469            // show orange button
16470            $lessonOrangeButtonRemaining = $this->triggerOrangeButton($this->Auth->User('id'), $teacherId, $userNotEligible, $unsupportedBrowser, $canLesson['lessonAvailable']);
16471
16472            if (
16473                $canLessonTextbook &&             # - can lesson with the textbook
16474                !$textbookForReservationOnly && # - textbook not for reserve only
16475                !$unsupportedBrowser &&         # - supported browser
16476                $userDuplicateLesson &&         # - has lesson with other teacher
16477                !$this->isStudySapuriTosUser &&    # - not sapuri TOS user
16478                !in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')]) && 
16479                !in_array($user['User']['payment_plan_id'], Configure::read('payment_plan_lightplan'))  # - not lite plan user
16480            ) {
16481                $canMidwayLesson = true;
16482            }
16483        } //end !$isGuestViewer
16484    
16485        $isRedLamp = isset($data['redLamp']) && $data['redLamp'] == "1" ? true : false;
16486        $isRedLamp = (isset($teacherStatus['status']) && $teacherStatus['status'] == 5) ? true : $isRedLamp;
16487        $showLoader = $isGuestViewer ? true : false;    
16488        $suddenLessonFlg = false;
16489        $canDoLive = UserTable::canJoinLiveViewing($user['User']);
16490    
16491        if (
16492            $isReserved && 
16493            (
16494                $this->isStudySapuriUser || 
16495                $this->isStudySapuriTosUser || 
16496                in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')])
16497            )
16498        ) {
16499            $canDoLive = false;
16500        }
16501    
16502        if(
16503            !$isViewer && 
16504            !$isEmergencyLesson && 
16505            !$isReservedCanSuddenLesson & 
16506            !$canMidwayLesson &&
16507            !$isReserved
16508        ) {
16509            if($teacherStatusColor == 'wait') {
16510                if((!$canLessonTextbook && $this->isStudySapuriUser) || $membershipTypeReservationOnly) {
16511                    $isBusy = true;
16512                }
16513    
16514                if(!( !$canLessonTextbook && $this->isStudySapuriUser ) && !$membershipTypeReservationOnly) {
16515                    $suddenLessonFlg = true;
16516                }
16517            }
16518    
16519            if($teacherStatusColor == 'lesson' || $teacherStatusColor == 'offline') {
16520                if(!($unsupportedBrowser && $teacherStatusColor == 'lesson') || !$membershipTypeReservationOnly) {
16521                    
16522                    if($membershipTypeBlueBtn) {
16523                        $suddenLessonFlg = true;
16524                        $teacherStatusColor = 'wait';
16525                    }
16526                }
16527            }
16528        }
16529    
16530        $canEmergencyLesson = false;
16531        $emergencyBreakTime = ['status' => false];        
16532        $currentMinutes = date("i");
16533        $currentHour = date("H");        
16534
16535        if ($isEmergencyLesson) {
16536            if ($this->isStudySapuriTosUser) {
16537                $nextEmergencySlot = $this->LessonSchedule->getEmergencyTimeSlot();
16538                $nextReserveSlot = $this->LessonSchedule->getNextReservationTimeSlot();
16539                $queryCondition['fields'][] = "(
16540                    ((select smb.id from shift_work_meal_breaks as smb where smb.lesson_time >= '{$nextReserveSlot['start']}' and smb.lesson_time <= '{$nextReserveSlot['end']}' and smb.teacher_id = Teacher.id limit 1) IS NULL) AND 
16541                    ((Select rs.id from lesson_schedules as rs where rs.lesson_time >= '{$nextEmergencySlot['start']}' and rs.lesson_time <= '{$nextEmergencySlot['end']}' and rs.status = 1 and rs.teacher_id = Teacher.id limit 1) IS NULL)
16542                    ) as can_emergency_lesson";
16543                $queryCondition['fields'][] = "((Select rs.id from lesson_schedules as rs where rs.lesson_time >= '{$nextReserveSlot['start']}' and rs.lesson_time <= '{$nextReserveSlot['end']}' and rs.status = 1 and rs.user_id = {$studentId} limit 1) IS NULL) 
16544                    as student_no_next_reservation";
16545            }
16546
16547            $commonTeacherStatusParams = array(
16548                'page_display' => 'listTeacher',
16549                'query_conditions' => $queryCondition
16550            );
16551            $emergencyLessonOnair = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
16552            
16553            if (
16554                $this->isStudySapuriTosUser &&
16555                !$isReserved &&
16556                isset($emergencyLessonOnair[0]['can_emergency_lesson']) && 
16557                isset($emergencyLessonOnair[0]['student_no_next_reservation']) && 
16558                $emergencyLessonOnair[0]['can_emergency_lesson'] && # -can emergency
16559                $emergencyLessonOnair[0]['student_no_next_reservation']    # - no next reservation
16560            ) {
16561                $canEmergencyLesson = true;
16562            }
16563
16564            # ~if emergency lesson break time
16565            if ( !$isReserved && (($currentMinutes >= 26 && $currentMinutes <= 29) || ($currentMinutes >= 56 && $currentMinutes <= 59))) {
16566                $canEmergencyLesson = false;
16567                $emergencyBreakTime['status'] = true;
16568                $emergencyBreakTime['time_span'] = '['.$currentHour.'時26分 ~ '.$currentHour.'時30分]['.$currentHour.'時56分 ~ '.$currentHour.'時00分]';
16569                $emergencyBreakTime['time_return'] = '['.$currentHour.'時30分]['.$currentHour.'時00分]';
16570            }
16571        }
16572    
16573        $isAvatar = $api['CommonTeacherStatus']['Teacher']['avatar_flg'] == 1 || $api['CommonTeacherStatus']['Teacher']['avatar_parent_flg'] == 1 ? true : false;
16574    
16575        // lesson alert
16576        $lessonAlertMsg = [];
16577        $lessonAlertStatus = '';
16578    
16579        // if emergency lesson break time
16580        if ($isEmergencyLesson && $emergencyBreakTime['status']) {
16581            $lessonAlertMsg = [
16582                ['text' => __d('waiting','しばらくお待ちください。')],
16583                ['text' => sprintf(__d('waiting','%sの間は緊急時予約レッスンにご入室いただけません。'), $emergencyBreakTime['time_span'])],
16584                ['text' => sprintf(__d('waiting','%sまでお待ちください。'), $emergencyBreakTime['time_return'])]
16585            ];
16586            $lessonAlertStatus = 'emergency_lesson_break_time';
16587        }
16588    
16589        if (
16590            (isset($exceedDailyLimit) && $exceedDailyLimit) &&
16591            !$isReserved &&
16592            !$isAvatar
16593        ) {
16594            $lessonAlertMsg = [
16595                ['text' => __d('waiting','同一講師との連続した今すぐレッスンはレッスン完了から60分空けて再度受講が可能となります (講師の独占を緩和するため) 。')],
16596                ['text' => __d('waiting','※異なる講師を選択した場合は何度でも連続で今すぐレッスンの受講が可能です (今すぐレッスン回数無制限) 。')],
16597                ['text' => __d('waiting','※回線不具合等で短時間レッスンとなった場合は、レッスン合計時間が25分に達するまでの間は同一講師と連続で今すぐレッスンの受講が可能です。')]
16598            ];
16599            $lessonAlertStatus = 'exceed_daily_limit';
16600        }
16601    
16602        // set localize url
16603        if (
16604            isset($get['la']) && in_array($get['la'], array_flip(Configure::read('pc_allowed_currencies'))) &&
16605            $get['la'] != Configure::read('default.user_language')
16606        ) {
16607            $localizeUrl = myTools::getUrl() . '/' . $get['la'];
16608        } else {
16609            $localizeUrl = myTools::getUrl();
16610        }
16611    
16612        $displayFamilyAlert = false;
16613        if (
16614            isset($this->sharedUserData['User']['parent_id']) &&
16615            !is_null($this->sharedUserData['User']['parent_id'])
16616        ) {
16617            $parent = $this->User->find('first', array(
16618                'fields' => array(
16619                    'User.id',
16620                    'User.hash16',
16621                    'User.charge_flg'
16622                ),
16623                'conditions' => array(
16624                    'User.id' => $this->sharedUserData['User']['parent_id']
16625                ),
16626                'recursive' => -1
16627            ));
16628    
16629            if ($parent && $parent['User']['charge_flg'] != 1) {
16630                $displayFamilyAlert = true;
16631            }
16632        }
16633    
16634        $device = false;
16635        if (strpos($ua, 'Silk') !== false) {
16636            $device = 'kindle';
16637        } else if (strpos($ua, 'Android') !== false) {
16638            $device = 'andriod';
16639        } else if (strpos($ua, 'iPhone') !== false) {
16640            $device = 'ios';
16641        } else if (strpos($ua, 'iPad') !== false) {
16642            $device = 'ios';
16643        } else if (strpos($ua, 'iPod') !== false) {
16644            $device = 'ios';
16645        } else {
16646            $device = 'pc';
16647        }
16648    
16649        $corporateIndividualUser = false;
16650        $corporateTypes = Configure::read('corporate_type_arr');
16651        $corporateTypeUserTable = myTools::getCoporateTypeUsingPaymentPlanId($user['User']['payment_plan_id']);
16652        if (isset($user['User']['corporate_id'])) {
16653            $corporateAdminPaymentMethod = $this->Corporate->getPaymentMethod($user['User']['corporate_id']);
16654            $corporateIndividualUser = $corporateAdminPaymentMethod == 1 ? true : false;
16655        }
16656    
16657        if (
16658            !$this->isStudySapuriUser &&
16659            $lessonType == Configure::read('lesson.type.reservation') &&
16660            ($uOnair && $uOnair['leave_lesson']) # - already left the reserved lesson
16661        ) {
16662            $isReservedCanLessonViewing = true;
16663        }
16664    
16665        $showTakeBusinessTestModal = false;
16666        if (isset($user['User']['corporate_id'])) {
16667            $showTakeBusinessTestModal = false;
16668            $isTakenBusinessTestFlg = (isset($user['User']['monthly_speaking_business_attended_flg'])) ? $user['User']['monthly_speaking_business_attended_flg'] : 0;
16669            $isMustTakeBusinessTestFlg = (isset($user['User']['monthly_speaking_business_attended_must_flg'])) ? $user['User']['monthly_speaking_business_attended_must_flg'] : 0;
16670            $corporateUserDate = time();
16671            $twentyPlusDayOfTheMonth = strtotime(date('Y-m-20'));
16672    
16673            if (
16674                ($isTakenBusinessTestFlg == 0 && $isMustTakeBusinessTestFlg == 1) &&
16675                !$isReserved &&
16676                (
16677                    $corporateUserDate >= $twentyPlusDayOfTheMonth ||
16678                    (
16679                        $userAdminFlag == 1 ||
16680                        (
16681                            isset($user["User"]["nickname"]) &&
16682                            strpos(strtoupper($user["User"]["nickname"]), '%%%TEST%%%') !== false
16683                        )
16684                    )
16685                )
16686            ) {
16687                $showTakeBusinessTestModal = true;
16688            }
16689        }        
16690    
16691        $liveLessonText = $liveData->lesson_flg ? __d('waiting','予約レッスン(LIVE)へ進む') : __d('waiting','予約レッスンへ進む');
16692        $button = $buttonStates[$stateButton];
16693    
16694        if(!$isGuestViewer) {
16695            $json = array_merge($json, [
16696                'button' => $button,
16697                'canDoLive' => $canDoLive,
16698                'canEmergencyLesson' => $canEmergencyLesson,
16699                'canLesson' => $canLesson,
16700                'canLessonTextbook' => $canLessonTextbook,
16701                'canMidwayLesson' => $canMidwayLesson,
16702                'checkBadge' => $checkBadge,
16703                'commonTeacher2' => $commonTeacher2,
16704                'corporateIndividualUser' => $corporateIndividualUser,
16705                'corporatePlanName' => isset($corporateTypeUserTable) ? (isset($corporateTypes[$corporateTypeUserTable]) ? $corporateTypes[$corporateTypeUserTable] : '') : '',
16706                'corporateType' => $corporateType,
16707                'corporateUserFlg' => $corporateUserFlg,
16708                'corpLightCondition' => $corpLightCondition1,
16709                'device' => $device,
16710                'displayFamilyAlert' => $displayFamilyAlert,
16711                'dummyLessonRoom' => $hasLessonBeforeActualTime,
16712                'emergencyBreakTime' => $emergencyBreakTime,
16713                'exceedDailyLimit' => isset($exceedDailyLimit) ? $exceedDailyLimit : false,
16714                'hasLessonBeforeActualTime' => $hasLessonBeforeActualTime,
16715                'homeFlg' => $api['CommonTeacherStatus']['Teacher']['home_flg'],
16716                'isAvatar' => $isAvatar,
16717                'isBusy' => $isBusy,
16718                'isEmergencyLesson' => $isEmergencyLesson,
16719                'isNormalLitePlanUser' => $isNormalLitePlanUser,
16720                'isRedLamp' => $isRedLamp,
16721                'isReserved' => $isReserved,
16722                'isReservedCanLessonViewing' => $isReservedCanLessonViewing,
16723                'isReservedCanSuddenLesson' => $isReservedCanSuddenLesson,
16724                'isStudySapuriTosUser' => $this->isStudySapuriUser,
16725                'isViewer' => $isViewer,
16726                'lessonAlertMsg' => $lessonAlertMsg,
16727                'lessonAlertStatus' => $lessonAlertStatus,
16728                'lessonOnOther' => $lessonOnOther,
16729                'lessonOrangeButtonRemaining' => $lessonOrangeButtonRemaining,
16730                'lessonType' => $lessonType,
16731                'liveData' => $liveData,
16732                'liveLessonFlg' => $liveLessonFlg ?? null,
16733                'liveLessonText' => $liveLessonText,
16734                'liveStatus' => $liveStatus,
16735                'localizeUrl' => $localizeUrl,
16736                'membershipTypeBlueBtn' => $membershipTypeBlueBtn,
16737                'membershipTypeReservationOnly' => $membershipTypeReservationOnly,
16738                'oOnair' => $oOnair,
16739                'uOnair' => $uOnair,
16740                'onGoingLesson' => $onGoingLesson,
16741                'paymentPlanId' => $user['User']['payment_plan_id'],
16742                'points' => $this->UsersPoint->getCurrentUserPoint($studentId),
16743                'redirectPlanUrl' => $redirectPlanUrl,
16744                'reservedLessonData' => $reservedLessonData,
16745                'sapuriCoin' => $sapuriCoin,
16746                'scheduleReservationData' => $scheduleReservationData,
16747                'showLoader' => $showLoader,
16748                'showNativeSpeakerWarning' => $showNativeSpeakerWarning,
16749                'showTakeBusinessTestModal' => $showTakeBusinessTestModal,
16750                'stateButton' => $stateButton,
16751                'stateButtonApi' => $api['teacher']['state_button'],
16752                'studentId' => $studentId,
16753                'suddenLessonFlg' => $suddenLessonFlg,
16754                'teacherAvatarFlg' => $api['CommonTeacherStatus']['Teacher']['avatar_flg'] == 1 ? true : false,
16755                'teacherLeaveNotice' => $teacherLeaveNotice,
16756                'teacherStatus' => $teacherStatus,
16757                'teacherStatusApi' => $_teacherStatus,
16758                'teacherStatusColor' => $teacherStatusColor,
16759                'textbookForReservationOnly' => $textbookForReservationOnly,
16760                'unverifiedSMS' => $stateButton == 7 ? true : false,
16761                'unsupportedBrowser' => $unsupportedBrowser,
16762                'use7DaysTrialModal' => $use7DaysTrialModal,
16763                'userAdminFlag' => $userAdminFlag,
16764                'userDoubleCheckFlag' => $userDoubleCheckFlag,
16765                'userDuplicateLesson' => $userDuplicateLesson,
16766                'userFailFlag' => $userFailFlag,
16767                'userMembershipType' => $this->userMembershipType,
16768                'userNativeOption' => $user['User']['native_option'],
16769                'userNotEligible' => $userNotEligible
16770            ]);
16771
16772            if($membershipTypeReservationOnly) {
16773                $json['lessonStartBtnText'] = __d('waiting','予約専用です');
16774            }
16775
16776            if($suddenLessonFlg) {
16777                if($use7DaysTrialModal) {
16778                    $json['suddenLessonStatus'] = 'use7DaysTrialModal';
16779                } else if (!empty(trim($redirectPlanUrl))) {
16780                    $json['suddenLessonStatus'] = 'redirectPlanUrl';
16781                } else if ($showNativeSpeakerWarning) {
16782                    $json['suddenLessonStatus'] = 'showNativeSpeakerWarning';
16783                } else if ($unsupportedBrowser) {
16784                    $json['suddenLessonStatus'] = 'unsupportedBrowser';
16785                } else if (!$canLessonTextbook) {
16786                    $json['suddenLessonStatus'] = 'cannotLessonTextbook';
16787                } else if (!empty($teacherLeaveNotice)) {
16788                    $json['suddenLessonStatus'] = 'teacherLeaveNotice';    
16789                }
16790
16791                if(!empty($json['suddenLessonStatus'])) {
16792                    $json['validateSuddenLessonFlg'] = false;
16793                } else {
16794                    $json['validateSuddenLessonFlg'] = true;
16795                }
16796            }
16797            
16798        } else if ($isViewer || $isGuestViewer) {
16799            $json = array_merge($json, [
16800                'canLesson' => $canLesson
16801            ]);
16802        }
16803
16804        if($env != 'PRODUCTION') {
16805            $json['api'] = $api;
16806            $json['commonTeacher2'] = $commonTeacher2;
16807            $json['emergencyLessonOnair'] = $emergencyLessonOnair;
16808            $json['tmpLessonOnAir'] = $tmp;
16809        }
16810    
16811        return json_encode($json);
16812    }
16813
16814    public function checkLessonStartButtonCounselor() {
16815        $this->autoRender = false;
16816        $this->layout = false;
16817        $userId = $this->Auth->user('id');
16818
16819        // if api token is not set
16820        if (empty($this->sharedUserData['User']['api_token'])) {
16821            $userApiToken = $this->User->generateAndSaveApiToken($userId);
16822            $this->Session->write('Auth.User.api_token', $userApiToken);
16823        }
16824
16825        myTools::initializeApiTunnel(array('TeachersCounselorDetailController'));
16826        $TeachersCounselorDetailController = new TeachersCounselorDetailController();
16827        $TeachersCounselorDetailController->params = [
16828            'nc_terminal_type' => 1, // pc
16829            'users_api_token' => $this->Auth->user('api_token'),
16830            'app_version' => Configure::read('max_sudden_lesson_counselor.app_version.2'),
16831            'device_type' => 2
16832        ];
16833        
16834        $data = json_decode($TeachersCounselorDetailController->counselorDetail(), true);
16835        $teacherId = $data['available_teacher'] ?? '';
16836        $status = $data['teacher']['status'] ?? '';
16837        $exceedDailyLimit = $data['exceed_daily_limit'] ? 1 : 0;
16838
16839        if ($status == 3) {
16840            $status = 2;
16841        } elseif ($status == 4) {
16842            $status = 3;
16843        }
16844
16845        return json_encode(
16846            array(
16847                'user_id' => $userId,
16848                'teacher_id' => $teacherId,
16849                'status' => $status,
16850                'exceed_daily_limit' => $exceedDailyLimit        
16851            )
16852        );
16853        
16854    }
16855
16856    public function checkLessonStartButtonCS() {
16857        $this->autoRender = false;
16858        $this->layout = false;
16859        $userId = $this->Auth->user('id');
16860        
16861        // if api token is not set
16862        if (empty($this->sharedUserData['User']['api_token'])) {
16863            $userApiToken = $this->User->generateAndSaveApiToken($userId);
16864            $this->Session->write('Auth.User.api_token', $userApiToken);
16865        }
16866
16867        myTools::initializeApiTunnel(array('TeachersCounselorDetailController'));
16868        $TeachersCounselorDetailController = new TeachersCounselorDetailController();
16869        $TeachersCounselorDetailController->params = [
16870            'nc_terminal_type' => 1, // pc
16871            'users_api_token' => $this->Auth->user('api_token'),
16872            'app_version' => Configure::read('max_sudden_lesson_counselor.app_version.2'),
16873            'device_type' => 2
16874        ];
16875
16876        if($this->userMembershipType === 12) {
16877            $csParams = array(
16878                'user_id' => $userId,
16879                'user_data' => $this->sharedUserData['User'],
16880                'customer_support_flg' => 1
16881            );
16882
16883            $data = json_decode( $this->LessonOnair->checkCounselorTeacherButtonStatus($csParams), true);
16884            $status = $data['res'] ?? '';
16885        } else {
16886            $data = json_decode($TeachersCounselorDetailController->customerSupportDetail(), true);
16887            $status = $data['teacher']['status'] ?? '';
16888        }
16889
16890        $teacherId = $data['available_teacher'] ?? '';
16891        $exceedDailyLimit = !empty($data['exceed_daily_limit']) ? 1 : 0;
16892
16893        if ($status == 3) {
16894            $status = 2;
16895        } elseif ($status == 4) {
16896            $status = 3;
16897        }
16898
16899        // Check if user exceeds daily limit for customer support lessons
16900        if ($userId) {
16901            $csList = $this->Teacher->getCustomerSupportTeachers();
16902            $csExceedLimitCheck = $this->LessonOnairsLog->checkExceedCSLimit($userId, $csList['customerSupportId']);
16903            if ($csExceedLimitCheck) {
16904                $exceedDailyLimit = 1;
16905                $status = 0;
16906            }
16907        }
16908
16909        return json_encode([
16910            'user_id' => $userId,
16911            'teacher_id' => $teacherId,
16912            'status' => $status,
16913            'exceed_daily_limit' => $exceedDailyLimit,
16914            'membership_type' => $this->userMembershipType
16915        ]);
16916    }
16917    public function updateLessonSystemTrouble() {
16918        $this->autoRender = false;
16919        $this->layout = false;
16920        $troubleResponse = false;
16921
16922        if ($this->request->is('ajax')) {
16923            $chatHash = $this->request->data['chat_hash'] ?? '';
16924            $status = $this->request->data['status'] ?? 0;
16925            $teacherID = $this->request->data['teacher_id'] ?? null;
16926            $storeMemcache = $this->request->data['store_memcache'] ?? 0;
16927
16928            if ($storeMemcache && $chatHash) {
16929                $memcached = new myMemcached();
16930                // $memcached->set(array(
16931                //     'key' => 'hide_connection_modal_flg_'.$teacherID.'-'.$chatHash,
16932                //     'value' => 1,
16933                //     'expire' => 86400 //-- 24hrs
16934                // ));
16935                $troubleResponse = true;
16936                $this->log("successfully added memcache");
16937            }
16938        }
16939
16940        return json_encode(array('result' => $troubleResponse));
16941    }
16942    
16943    public function setAppreciationModalFinish(){
16944        $this->autoRender = false;
16945        $this->layout = false;
16946
16947        if(empty($this->request->data['chat_hash'])){
16948            return false;
16949        }
16950
16951        $chat_hash = $this->request->data['chat_hash'];
16952
16953        if (!class_exists('myMemcached')) {
16954            App::uses('myMemcached', 'Lib');
16955        }
16956        $memcached = new myMemcached();
16957        $memcached->set(array(
16958            'key' => "appreciation_done_".$chat_hash,
16959            'value' => 1,
16960            'expire' => 86400 // 1 day
16961        ));
16962
16963        return true;
16964    }
16965}